|
Posted on 2010-10-06 11:53 成幸毅 阅读(316) 评论(0) 编辑 收藏 引用
题目意思是要求边有扩容之后能使流量加大,问这样的边有几条,这里要注意的是,最小割不一定就是这种边,但是这种边就一定是割了,因为假设可能有一条增光路上有和最小割相同容量的边,那么扩容了最小割也没用,所以一次DFS正向反向都不行,必须两次DFS。正的来一次,反向图从汇点来一次,标记1,2然后连接1和2的那条边就是可扩容边。假设x-.y是可扩容边,那么必定有,s->x和y->t存在。
【题目大意】
给出一张传输流量图,求给哪些边添加容量,可以增大最大流。 【解题思路】
实际上就是求割边,但这个割边必需是一头能被源到达,另一头能被汇到达。
【Code】
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> using namespace std;
#define MAXN 510 #define MAXM 10010 #define inf 1000000000
struct Edge { int to, from, flow, cap; int next, pair; //pair表示跟它是一对的另一边 };
int n, m; int source, sink; //源点和汇点 Edge edge[MAXM]; int cnt, pn[MAXN];
void addedge(int from, int to, int cap) //一次增加两条边 { edge[cnt].from = from; edge[cnt].to = to; edge[cnt].next = pn[from]; edge[cnt].cap = cap; edge[cnt].flow = 0; edge[cnt].pair = cnt + 1; pn[from] = cnt++;
//增加另一条边 edge[cnt].from = to; edge[cnt].to = from; edge[cnt].next = pn[to]; edge[cnt].cap = 0; edge[cnt].flow = 0; edge[cnt].pair = cnt - 1; pn[to] = cnt++; }
int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];
int ISAP() { int cur_flow,max_flow,u,tmp,neck,i; memset(dist,0,sizeof(dist)); memset(numb,0,sizeof(numb)); //初始化为0,不需要反向bfs了 for(i = 1 ; i <= n ; ++i) curedge[i] = pn[i]; numb[n] = n; max_flow = 0; u = source; while(dist[source] < n) { if(u == sink) { cur_flow = inf + 1; //!!!!注意这里要大于inf for(i = source; i != sink; i = edge[curedge[i]].to) if(cur_flow > edge[curedge[i]].cap) { neck = i; cur_flow = edge[curedge[i]].cap; } for(i = source; i != sink; i = edge[curedge[i]].to) { tmp = curedge[i]; edge[tmp].cap -= cur_flow; edge[tmp].flow += cur_flow; tmp = edge[tmp].pair; edge[tmp].cap += cur_flow; edge[tmp].flow -= cur_flow; } max_flow += cur_flow; u = neck; } for(i = curedge[u]; i != -1; i = edge[i].next) if(edge[i].cap > 0 && dist[u] == dist[edge[i].to]+1) break; if(i != -1) { curedge[u] = i; pre[edge[i].to] = u; u = edge[i].to; } else { if(0 == --numb[dist[u]]) break; curedge[u] = pn[u]; for(tmp = n,i = pn[u]; i != -1; i = edge[i].next) if(edge[i].cap > 0) tmp = tmp<dist[edge[i].to]?tmp:dist[edge[i].to]; dist[u] = tmp + 1; ++numb[dist[u]]; if(u != source) u = pre[u]; } } return max_flow; }
int mat[MAXN][MAXN]; bool vs[MAXN],vt[MAXN];
void dfs(int k, bool v[MAXN]) //求从k出发可以到达的所有顶点 { int i; v[k] = 1; for (i = 1; i <= n; i++) if (!v[i] && mat[k][i]) dfs(i, v); }
void work() { int i; memset(mat,0,sizeof(mat));
for (i = 1; i < cnt; i += 2) { if (edge[i].cap) //非满流边 { mat[edge[i].from][edge[i].to] = 1; } } memset(vs,0,sizeof(vs)); dfs(source, vs); //从0开始搜索 memset(mat,0,sizeof(mat)); for (i = 1; i < cnt; i += 2) { if (edge[i].cap) { mat[edge[i].to][edge[i].from] = 1; } } memset(vt,0,sizeof(vt)); dfs(sink,vt); //从n-1开始搜索
int ans = 0; for (i = 1; i < cnt; i += 2) { if (!edge[i].cap && vs[edge[i].from] && vt[edge[i].to]) ans++; } printf("%d\n",ans); }
int main() { int u, v, w; // freopen("in.txt","r",stdin); scanf("%d %d",&n,&m); memset(pn,0xff,sizeof(pn)); cnt = 1; while (m--) { scanf("%d %d %d",&u,&v,&w); u++; v++; addedge(u,v,w); } source = 1; sink = n; u = ISAP(); work(); return 0; }
|