个人整理网络流
Posted 大米饼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了个人整理网络流相关的知识,希望对你有一定的参考价值。
说明:S,表示超级原点,T表示超级汇点,<i,j,k(,l)>表示i到j建边,流量为k(,费用为l),某些题由于没有及时纠正码风,板子的常数较大。。。。。
bzoj4177 Mike的农场
题解:考虑割,养牛的收益为a[i],养羊b[i],对于每个位置<S,i,ai> <i,T,bi>分别表示养牛和养羊,对于两个互相影响的位置<i,j,ci>;做最小割可以满足前两个限制 ;第三个限制,如果全养牛可以获得d,新建一个点x,考虑要求全养牛的位置为集合为s,<S,x,d> , <x,si,inf> , 当si中有一个没有被割,那么<S,x,d>一定被割,养羊同理对T建,设最小割为C,ans = $( \\sum (a[i]+b[i]) + \\sum c[i] ) – C $
1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 const int N=10010,M=80010; 5 int S,T,n,m,k,o,hd[N],cur[N],vis[N],d[N]; 6 struct Edge{int v,nt,c,f;}E[M<<1]; 7 char gc(){ 8 static char*p1,*p2,s[1000000]; 9 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 10 return(p1==p2)?EOF:*p1++; 11 } 12 int rd(){ 13 int x=0; char c=gc(); 14 while(c<\'0\'||c>\'9\')c=gc(); 15 while(c>=\'0\'&&c<=\'9\')x=(x<<1)+(x<<3)+c-\'0\',c=gc(); 16 return x; 17 } 18 void adde(int u,int v,int c){ 19 E[o]=(Edge){v,hd[u],c,0};hd[u]=o++; 20 E[o]=(Edge){u,hd[v],0,0};hd[v]=o++; 21 } 22 queue<int>q; 23 bool bfs(){ 24 for(int i=S;i<=T;i++)vis[i]=d[i]=0; 25 vis[S]=d[S]=1;q.push(S); 26 while(!q.empty()){ 27 int u=q.front();q.pop(); 28 for(int i=hd[u],v;~i;i=E[i].nt)if(E[i].c>E[i].f){ 29 if(!vis[v=E[i].v])vis[v]=1,d[v]=d[u]+1,q.push(v); 30 } 31 } 32 return vis[T]; 33 } 34 int dfs(int u,int F){ 35 if(u==T||!F)return F; 36 int flow=0,f; 37 for(int i=cur[u];~i;i=E[i].nt){ 38 int v=E[cur[u]=i].v; 39 if(d[v]==d[u]+1&&(f=dfs(v,min(E[i].c-E[i].f,F)))){ 40 flow+=f,F-=f; 41 E[i].f+=f,E[i^1].f-=f; 42 if(!F)break; 43 } 44 } 45 return flow; 46 } 47 int dinic(){ 48 int flow=0; 49 while(bfs()){for(int i=S;i<=T;i++)cur[i]=hd[i];flow+=dfs(S,inf);} 50 return flow; 51 } 52 int main(){ 53 freopen("bzoj4177.in","r",stdin); 54 freopen("bzoj4177.out","w",stdout); 55 n=rd();m=rd();k=rd(); 56 S=0,T=n+k+1; 57 for(int i=S;i<=T;i++)hd[i]=-1; 58 int ans=0; 59 for(int i=1,x;i<=n;i++){adde(S,i,x=rd());ans+=x;} 60 for(int i=1,x;i<=n;i++){adde(i,T,x=rd());ans+=x;} 61 for(int i=1,x,y,z;i<=m;i++){ 62 x=rd();y=rd();z=rd(); 63 adde(x,y,z); 64 adde(y,x,z); 65 } 66 for(int i=1,t,a,b;i<=k;i++){ 67 t=rd();a=rd();b=rd(); 68 ans+=b; 69 if(!a){ 70 adde(S,i+n,b); 71 for(int j=1;j<=t;j++)adde(i+n,rd(),inf); 72 }else{ 73 adde(i+n,T,b); 74 for(int j=1;j<=t;j++)adde(rd(),i+n,inf); 75 } 76 } 77 ans -= dinic(); 78 printf("%d\\n",ans); 79 return 0; 80 } 81 82 83 84 85 86 87 88 89 90 //一个很好的割; 91 //每个点(S,i,a[i]) (i,T,b[i]); 92 //相同时代价 (x,y,b) 93 //集合的贡献:新建n+i号节点表示:a==0 , (S,n+i,b) (n+i,si,inf) ; a==1 (si,n+i,inf) (n+i,T,b); 94 //用总的正值减去最小割即可; 95 //注意第三步; 96 //20181210 97
bzoj3504 [cqoi2014]危桥
题解:a1->a2 an次,b1->b2 bn次 , 边有通过次数的限制;直接跑最大流判断会有问题,因为可能会有a1->b2 , b1->a2的路径充当流量,交换a1,a2再反向跑一边即可;
1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 const int N=55,M=2510; 5 int S,T,n,o,a1,a2,an,b1,b2,bn,hd[N],vis[N],cur[N],d[N],in[N],out[N],tot; 6 struct Edge{int v,nt,c,f;}E[M<<1]; 7 void adde(int u,int v,int c){ 8 E[o]=(Edge){v,hd[u],c,0};hd[u]=o++; 9 E[o]=(Edge){u,hd[v],0,0};hd[v]=o++; 10 } 11 queue<int>q; 12 bool bfs(){ 13 for(int i=S;i<=T;i++)vis[i]=d[i]=0; 14 vis[S]=d[S]=1;q.push(S); 15 while(!q.empty()){ 16 int u=q.front();q.pop(); 17 for(int i=hd[u],v;~i;i=E[i].nt)if(E[i].c>E[i].f){ 18 if(!vis[v=E[i].v])vis[v]=1,d[v]=d[u]+1,q.push(v); 19 } 20 } 21 return vis[T]; 22 } 23 int dfs(int u,int F){ 24 if(!F||u==T)return F; 25 int flow=0,f; 26 for(int i=cur[u];~i;i=E[i].nt){ 27 int v=E[cur[u]=i].v; 28 if(d[v]==d[u]+1&&(f=dfs(v,min(F,E[i].c-E[i].f)))){ 29 flow+=f,F-=f; 30 E[i].f+=f,E[i^1].f-=f; 31 if(!F)break; 32 } 33 } 34 return flow; 35 } 36 int dinic(){ 37 int flow=0; 38 while(bfs()){for(int i=S;i<=T;i++)cur[i]=hd[i];flow+=dfs(S,inf);} 39 return flow; 40 } 41 int main(){ 42 freopen("bzoj3504.in","r",stdin); 43 freopen("bzoj3504.out","w",stdout); 44 while(~scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)){ 45 a1++,a2++,b1++,b2++; 46 o=0;S=0;T=n+1; 47 for(int i=S;i<=T;i++)hd[i]=-1; 48 for(int i=1;i<=n;i++){ 49 char ch[51];scanf("%s",ch+1); 50 for(int j=1;j<=n;j++){ 51 if(ch[j]==\'O\')adde(i,j,1); 52 else if(ch[j]==\'N\')adde(i,j,inf); 53 } 54 } 55 adde(S,a1,an);adde(a2,T,an); 56 int pre1=hd[S],pre2=hd[T],pre3=hd[b1],pre4=hd[b2]; 57 adde(S,b1,bn);adde(b2,T,bn); 58 if(dinic()!=an+bn){puts("No");continue;} 59 o-=4;for(int i=0;i<o;i++)E[i].f=0; 60 hd[S]=pre1,hd[T]=pre2,hd[b1]=pre3,hd[b2]=pre4; 61 adde(S,b2,bn);adde(b1,T,bn); 62 puts(dinic()==an+bn?"Yes":"No"); 63 } 64 return 0; 65 } 66 67 68 69 70 71 72 73 //一个比较巧妙的路径; 74 //通过yy可以发现,将第二条路径反向再做一遍就可以避免错误; 75 //20181210 76 77 78
bzoj2039[2009国家集训队]employee
题解:首先<i,T,Ai>表示是否选择购买,考虑每对经理(i,j) , <S,i,Ei,j> <S,j,Ei,j> <i,j,2*Ei,j> , 这个网络可以化简:<S,i,$\\sum_{j}Ei,j$> <i,T,Ai> <i,j,2*Ei,j>,假设最小割为C,E的和为Sum,ans = 2*Sum – C;
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define inf 1e18 4 using namespace std; 5 const int N=1010,M=2000010; 6 int n,o,hd[N],vis[N],d[N],cur[N]; 7 struct Edge{int v,nt; ll c,f;}E[M<<1]; 8 char gc(){ 9 static char*p1,*p2,s[1000000]; 10 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 11 return(p1==p2)?EOF:*p1++; 12 } 13 ll rd(){ 14 ll x=0; char c=gc(); 15 while(c<\'0\'||c>\'9\')c=gc(); 16 while(c>=\'0\'&&c<=\'9\')x=(x<<1)+(x<<3)+c-\'0\',c=gc(); 17 return x; 18 } 19 void adde(int u,int v,ll c){ 20 E[o]=(Edge){v,hd[u],c,0};hd[u]=o++; 21 E[o]=(Edge){u,hd[v],0,0};hd[v]=o++; 22 } 23 queue<int>q; 24 bool bfs(){ 25 for(int i=0;i<=n+1;i++)vis[i]=d[i]=0; 26 vis[0]=d[0]=1;q.push(0); 27 while(!q.empty()){ 28 int u=q.front();q.pop(); 29 for(int i=hd[u],v;~i;i=E[i].nt)if(E[i].c>E[i].f){ 30 if(!vis[v=E[i].v])vis[v]=1,d[v]=d[u]+1,q.push(v); 31 } 32 } 33 return vis[n+1]; 34 } 35 ll dfs(int u,ll F){ 36 if(u==n+1||!F)return F; 37 int flow=0,f; 38 for(int i=cur[u];~i;i=E[i].nt){ 39 int v=E[cur[u]=i].v; 40 if(d[v]==d[u]+1&&(f=dfs(v,min(E[i].c-E[i].f,F)))){ 41 flow+=f,F-=f; 42 E[i].f+=f,E[i^1].f-=f; 43 if(!F)break; 44 } 45 } 46 return flow; 47 } 48 int dinic(){ 49 int flow=0,f; 50 while(bfs()){ 51 for(int i=0;i<=n+1;i++)cur[i]=hd[i]; 52 while(f=dfs(0,inf))flow+=f; 53 } 54 return flow; 55 } 56 int main(){ 57 freopen("bzoj2039.in","r",stdin); 58 freopen("bzoj2039.out","w",stdout); 59 n=rd();for(int i=0;i<=n+1;i++)hd[i]=-1; 60 for(int i=1;i<=n;i++)adde(i,n+1,rd()); 61 ll ans=0; 62 for(int i=1;i<=n;i++){ 63 ll sum=0,x; 64 for(int j=1;j<=n;j++){ 65 x=rd();sum+=x; 66 adde(i,j,x<<1); 67 } 68 adde(0,i,sum); 69 ans+=sum; 70 } 71 ans-=dinic(); 72 printf("%lld\\n",ans); 73 return 0; 74 } 75 76 77 78 79 80 81 82 83 84 85 86 //这题卡常???? 87 //luogu的我没过,开了O(2)好像也不行,bzoj勉强过了。。。。; 88 //(S,i,\\sum ei,j) (i,j,2*ei,j) (i,T,ai) 89 //20181210 90 91 92 93
bzoj1797[AHOI2009]mincut
题解:
先做一遍最大流,考虑残量网络(要考虑反向边),
如果一条边有可能不满流那么它一定不可能为任何个割的一部分,一定满流那么它一定为某个割的一部分;
考虑一个最小割对应的划分集合S集合T集,跨越ST集合的边为割,那么残网中一定只存在T->S的边,假设存在S-T的边,要么为某个S->T的正向边要么为某个T->S反向边,前者不符合割后者不符合最小(感性理解吧。。。。);
所以在残网中做scc,设i所在scc为bl[i] , 首先bl[S]!=bl[T],对于残网中的边(u,v):
①如果bl[u]==bl[v],一定不可能为割边
②如果bl[u]!=bl[v]且bl[u]==bl[T]&&bl[v]==bl[S],则一定为割边,否则在缩点后的残网DAG上一定可以有一个另外的割;
1 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 const int N=4010,M=60010; 5 int S,T,n,m,o,hd[N],cur[N],vis[N],d[N],dfn[N],low[N],idx,bl[N],cnt; 6 struct Edge{int u,v,nt,c,f;}E[M<<1]; 7 void adde(int u,int v,int c){ 8 E[o]=(Edge){u,v,hd[u],c,0};hd[u]=o++; 9 E[o]=(Edge){v,u,hd[v],0,0};hd[v]=o++; 10 } 11 queue<int>q; 12 bool bfs(){ 13 for(int i=1;i<=n;i++)vis[i]=d[i]=0; 14 vis[S]=d[S]=1;q.push(S); 15 while(!q.empty()){ 16 int u=q.front();q.pop(); 17 for(int i=hd[u],v;~i;i=E[i].nt)if(E[i].c>E[i].f){ 18 if(!vis[v=E[i].v])vis[v]=1,d[v]=d[u]+1,q.push(v); 19 } 20 } 21 return vis[T]; 22 } 23 int dfs(int u,int F){ 24 if(u==T||!F)return F; 25 int flow=0,f; 26 for(int i=cur[u];~i;i=E[i].nt){ 27 int v=E[cur[u]=i].v; 28 if(d[v]==d[u]+1&&(f=dfs(v,min(F,E[i].c-E[i].f)))){ 29 flow+=f,F-=f; 30 E[i].f+=f,E[i^1].f-=f; 31 if(!F)break; 32 } 33 } 34 return flow; 35 } 36 int dinic(){ 37 int flow=0; 38 while(bfs()){ 39 for(int i=1;i<=n;i++)cur[i]=hd[i]; 40 flow+=dfs(S,inf); 41 } 42 return flow; 43 } 44 stack<int>s; 45 void tarjan(int u){ 46 dfn[u]=low[u]=++idx; 47 s.push(u); 48 for(int i=hd[u];~i;i=E[i].nt)if(E[i].c>E[i].f){ 49 int v=E[i].v; 50 if(dfn[v]){if(!d[v])low[u]=min(dfn[v],low[u]);} 51 else {tarjan(v);low[u]=min(low[v],low[u]);} 52 } 53 if(dfn[u]==low[u]){ 54 int v;++cnt; 55 do{ 56 v=s.top();s.pop(); 57 d[v]=1;bl[v]=cnt; XMPP协议扩展:XEP-0198 流管理(Stream Management)中文翻译(个人整理,难免有翻译错的地方,请多多指正)java内存流:java.io.ByteArrayInputStreamjava.io.ByteArrayOutputStreamjava.io.CharArrayReaderjava.io(代码片段