B - Internship (网络流关键割边)
Posted letlifestop
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B - Internship (网络流关键割边)相关的知识,希望对你有一定的参考价值。
题目链接:https://cn.vjudge.net/contest/281961#problem/B
题目大意:给你n个城市,中间有一些中转站,然后给你终点,再给你l条轨道以及流量,问你增加哪几条轨道的流量可以使得流到终点的流量增加。
具体思路:首先分析一波,一开始想的是找割边,但是只是找出割边是不可以的。举个例子 : s->u->t,这样的话,假设这两条边都是满流,都可以当做割边,但是如果只是增加割边的流量的话,会受到其他边的流量的限制,最终流量还是不会增加的,所以,换一个思路,我们先跑一遍最大流,然后观察残余网络的情况,如果一条边的起点和终点对应的起点作为另一条边的终点以及终点对应另一条边的起点的话,依旧是如果增加当前这条边的流量的话,还是可以增加流量的,这样关键割边就找出来了。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<queue> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<cstring> 7 #include<cstring> 8 #include<cmath> 9 #include<algorithm> 10 #include<map> 11 #include<vector> 12 using namespace std; 13 # define ll long long 14 const int maxn = 4e3+100; 15 # define inf 0x3f3f3f3f 16 int st,ed; 17 int prev[maxn]; 18 int head[maxn]; 19 int line[maxn]; 20 int vis1[maxn],vis2[maxn]; 21 struct node 22 { 23 int fr; 24 int to; 25 int flow; 26 int nex; 27 } edge[maxn]; 28 int num; 29 void init() 30 { 31 memset(head,-1,sizeof(head)); 32 memset(vis1,0,sizeof(vis1)); 33 memset(vis2,0,sizeof(vis2)); 34 num=0; 35 } 36 void addedge(int fr,int to,int flow) 37 { 38 edge[num].to=to; 39 edge[num].fr=fr; 40 edge[num].flow=flow; 41 edge[num].nex=head[fr]; 42 head[fr]=num++; 43 edge[num].to=fr; 44 edge[num].fr=to; 45 edge[num].flow=0; 46 edge[num].nex=head[to]; 47 head[to]=num++; 48 } 49 bool bfs() 50 { 51 memset(prev,-1,sizeof(prev)); 52 prev[st]=1; 53 queue<int>q; 54 q.push(st); 55 while(!q.empty()) 56 { 57 int top=q.front(); 58 q.pop(); 59 for(int i=head[top]; i!=-1; i=edge[i].nex) 60 { 61 int temp=edge[i].to; 62 if(prev[temp]==-1&&edge[i].flow>0) 63 { 64 prev[temp]=prev[top]+1; 65 q.push(temp); 66 } 67 } 68 } 69 return prev[ed]!=-1; 70 } 71 int dfs(int u,int flow) 72 { 73 if(u==ed) 74 return flow; 75 int res=0; 76 for(int i=head[u]; i!=-1; i=edge[i].nex) 77 { 78 int t=edge[i].to; 79 if(prev[t]==(prev[u]+1)&&edge[i].flow>0) 80 { 81 int temp=dfs(t,min(flow,edge[i].flow)); 82 edge[i].flow-=temp; 83 edge[i^1].flow+=temp; 84 res+=temp; 85 flow-=temp; 86 if(flow==0) 87 break; 88 } 89 } 90 if(res==0) 91 prev[u]=-1; 92 return res; 93 } 94 void dinic() 95 { 96 int ans=0; 97 while(bfs()) 98 { 99 ans+=dfs(st,inf); 100 } 101 } 102 void dfs1(int u) 103 { 104 vis1[u]=1; 105 for(int i=head[u]; i!=-1; i=edge[i].nex) 106 { 107 int v=edge[i].to; 108 if(!vis1[v]&&edge[i].flow) 109 dfs1(v); 110 } 111 } 112 void dfs2(int u) 113 { 114 vis2[u]=1; 115 for(int i=head[u]; i!=-1; i=edge[i].nex) 116 { 117 int v=edge[i].to; 118 if(!vis2[v]&&edge[i^1].flow) 119 { 120 dfs2(v); 121 } 122 } 123 } 124 int main() 125 { 126 int n,m,l; 127 while(~scanf("%d",&n)) 128 { 129 if(n==0) 130 break; 131 init(); 132 scanf("%d %d",&m,&l); 133 st=n+m+1; 134 ed=0; 135 int t1,t2,t3; 136 for(int i=0; i<l; i++) 137 { 138 scanf("%d %d %d",&t1,&t2,&t3); 139 line[i]=num; 140 addedge(t1,t2,t3); 141 } 142 for(int i=1; i<=n; i++) 143 { 144 addedge(st,i,inf); 145 } 146 dinic(); 147 dfs1(st); 148 dfs2(ed); 149 // cout<<1<<endl; 150 int flag=1; 151 for(int i=0; i<l; i++) 152 { 153 // cout<<i<<endl; 154 if(edge[line[i]].flow==0&&vis1[edge[line[i]].fr]&&vis2[edge[line[i]].to]) 155 { 156 // cout<<i<<endl; 157 if(flag) 158 { 159 printf("%d",i+1); 160 flag=0; 161 } 162 else 163 { 164 printf(" %d",i+1); 165 } 166 } 167 } 168 printf(" "); 169 } 170 return 0; 171 }
以上是关于B - Internship (网络流关键割边)的主要内容,如果未能解决你的问题,请参考以下文章