博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
4067: [Ctsc2015]gender 动态规划 网络流
阅读量:4599 次
发布时间:2019-06-09

本文共 4507 字,大约阅读时间需要 15 分钟。

国际惯例的题面:

首先这题是缺少两个隐藏条件的:
第一个是这k条链的起点和终点所在的层是对齐的,也就是说不会出现两条链错开的情况,且这张图恰好由n层组成;
第二个就是任意一个点都包含在与链上的点直接或间接相关的同一层中,不存在与链无关的孤立层。
(如果缺少第一个条件这题是基本没法做的,分类讨论细节太多;第二个讨论倒是无关紧要,你钦定孤立层的点都在第一层就好了)
(别问我怎么知道的,第一个是找学长问出来的,第二个是调?教!某神犇的AC代码(把他WA掉)试出来的)
然后就是怎么做的问题。
观察到那个ln十分不好处理,我们可以枚举它。反正ln增长很慢,总共就40+种取值。
同时发现k很小,这提醒我们,每层的关键点很少,我们能否状压呢?
我们先枚举那个ln的值,定义f[depth][statement][different]表示考虑从第1到depth层,当前层(第depth层)修改状态为statement,总共产生的链上相邻点修改状态不同的数量为different的最大收益。
f[depth][statement][different] = max( f[depth-1][last_statement][different-diff(statement^last_statement)] + calc(depth,statement) )。
考虑如何计算第depth层,状态为statement时的最大代价。
点要么改要么不改,二种状态必选其一,不是2-sat就是最小割。
而2-sat只能解决判定性问题,所以铁定是最小割了。
考虑怎么建图:
(参考"Bzoj3438: 小M的作物"和"3894: 文理分科"的建图,然而你都没有写过也没关系,我会叙述清楚)
首先我们累加能获得的所有权值,再减去最后的最小割。
我们钦定对于一个点,如果在最小割中与源点相连,代表它保持原状,与汇点相连代表它被改变性别。
那么这个点与源点的边权就是对它进行改变的代价,与汇点的边权就是让它维持原状的代价。
(对于链上的点(显然状态被statement确定),我们让它只与源点汇点连inf边表示它被钦定保持原状/进行改变)
对于一条原图中的边(就是"繁衍关系"),在两个点都不被改变时产生价值di,我们为可以为它新建一个点,从源点向这个点连容量di的边,再从这个点向依赖的两个点ui,vi连接容量为inf的边,代表如果要把ui或者vi放到与汇点相连的集合,则必须割掉这条边的权值。
两个点都改变时产生的价值di*bi建图同理。
然后就是一些细节,比如层内的代价只和枚举的ln,层数depth和状态statement有关,那么我们对这样的三元组可以只跑一次网络流而不是每次进行计算。
网络流重建图的时候不要memset整个数组,用多少memset多少,否则TLE。
对每个点转换一下坐标,把点的编号转化为它在层内的编号,这样能使得每次网络流点的编号连续,减少memset的时间。
(然后就是我人傻用了一堆vector导致大常数的代码了)
代码:

1 #pragma GCC optimize(2)  2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #define debug cout 10 using namespace std; 11 const int maxn=1e3+1e2,maxe=5e4+1e3,maxs=1<<4; 12 const int inf=0x3f3f3f3f,minf=0xefefefef; 13 14 int chain[5][maxn],id[maxn],c[maxn],dep[maxn],rid[maxn]; // id of chain . 15 vector
pts[maxn]; // points of each level . 16 struct Edge { int u,v,b,d;}ine[maxe]; 17 vector
es[maxn]; // edge of each level. 18 int f[55][1<<4][210],ln[210]; // f[level][statement][diffs] 19 int n,m,k,p,full,ans; 20 21 namespace Flow { 22 int s[maxe],t[maxe<<2],nxt[maxe<<2],f[maxe<<2],cnt=1; 23 int dep[maxe],st,ed; 24 inline void coredge(int from,int to,int flow) { 25 t[++cnt] = to , f[cnt] = flow , nxt[cnt] = s[from] , s[from] = cnt; 26 } 27 inline void singledge(int from,int to,int flow) { 28 coredge(from,to,flow) , coredge(to,from,0); 29 } 30 inline bool bfs() { 31 memset(dep,-1,sizeof(int)*(ed+1)) , dep[st] = 0; 32 queue
q; q.push(st); 33 while( q.size() ) { 34 const int pos = q.front(); q.pop(); 35 for(int at=s[pos];at;at=nxt[at]) 36 if( f[at] && !~dep[t[at]] ) 37 dep[t[at]] = dep[pos] + 1 , q.push(t[at]); 38 } 39 return ~dep[ed]; 40 } 41 inline int dfs(int pos,int flow) { 42 if( pos == ed ) return flow; 43 int ret = 0 , now = 0; 44 for(int at=s[pos];at;at=nxt[at]) 45 if( f[at] && dep[t[at]] > dep[pos] ) { 46 now = dfs(t[at],min(flow,f[at])) , 47 ret += now , flow -= now , f[at] -= now , f[at^1] += now; 48 if( !flow ) return ret; 49 } 50 if( !ret ) dep[pos] = -1; 51 return ret; 52 } 53 inline int dinic() { 54 int ret = 0; 55 while( bfs() ) ret += dfs(st,inf); 56 return ret; 57 } 58 inline void reset() { 59 memset(s,0,sizeof(int)*(ed+1)) , cnt = 1; 60 } 61 } 62 63 inline int build(int dep,int sta,int mul) { 64 using namespace Flow; 65 st = pts[dep].size() + ( es[dep].size() * 2 ) + 1 , ed = st + 1 , reset(); 66 #define cov(x,t) (x*2+1+t+pts[dep].size()) 67 int ret = 0; 68 for(unsigned i=0;i
> ( id[p] - 1 ) ) & 1 ) singledge(rid[p],ed,inf) , ret -= c[p]; 72 else singledge(st,rid[p],inf); 73 } else singledge(st,rid[p],c[p]) , singledge(rid[p],ed,0); 74 } 75 for(unsigned i=0;i
<< k;136 for(int i=1;i<=m;i++) scanf("%d",c+i);137 for(int i=1;i<=k;i++) for(int j=1;j<=n;j++) scanf("%d",chain[i]+j) , id[chain[i][j]] = i;138 for(int i=1;i<=p;i++) {139 scanf("%d%d%d%lf",&ine[i].u,&ine[i].v,&ine[i].d,&dd) , ine[i].b = floor( ine[i].d * dd ) , 140 ufs.merge(ine[i].u,ine[i].v);141 }142 for(int i=1;i<=k;i++) for(int j=1;j<=n;j++) dep[ufs.findfa(chain[i][j])] = j;143 for(int i=1;i<=m;i++) {144 dep[i] = dep[ufs.findfa(i)];145 if( !dep[i] ) dep[i] = dep[ufs.findfa(i)] = 1;146 pts[dep[i]].push_back(i) , rid[i] = pts[dep[i]].size();147 }148 for(int i=1;i<=p;i++) es[dep[ine[i].u]].push_back(ine[i]);149 for(int i=ln[0];i<=ln[n*k];i++) dp(i);150 printf("%d\n",ans);151 return 0;152 }
View Code

キミの未来が私の未来
你的未来 就是 我的未来
キミが居るなら何も怖くない
只要有你在 我便什么都不怕
二人を繋ぐ 重ねた手と手
维系你我的 交叠的手与手
離れないように強く握りしめて行こう
为再也不离不弃 往后也用力紧握
誰よりも優しく強い
比任何人 都温柔坚强
誰よりも脆く弱い人
比任何人 都脆弱的人
たくさんの痛みを知って
遍尝世间万千苦痛
悲しいことも隠して笑う
藏起伤悲强颜欢笑

转载于:https://www.cnblogs.com/Cmd2001/p/8974862.html

你可能感兴趣的文章
蓝牙模块选择经验谈
查看>>
java中==和equals
查看>>
CCActionPageTurn3D
查看>>
python random
查看>>
esp32-智能语音-cli(调试交互命令)
查看>>
netty与MQ使用心得
查看>>
关于dl dt dd 文字过长换行在移动端显示对齐的探讨总结
查看>>
swoolefy PHP的异步、并行、高性能网络通信引擎内置了Http/WebSocket服务器端/客户端...
查看>>
Python学习笔记
查看>>
unshift()与shift()
查看>>
使用 NPOI 、aspose实现execl模板公式计算
查看>>
行为型模式:中介者模式
查看>>
How to Notify Command to evaluate in mvvmlight
查看>>
33. Search in Rotated Sorted Array
查看>>
461. Hamming Distance
查看>>
Python垃圾回收机制详解
查看>>
{面试题1: 赋值运算符函数}
查看>>
Node中没搞明白require和import,你会被坑的很惨
查看>>
Python 标识符
查看>>
Python mysql 创建连接
查看>>