poj 3204(最小割--关键割边)
2016-06-03 21:17
274 查看
Ikki's Story I - Road Reconstruction
Description
Ikki is the king of a small country – Phoenix, Phoenix is so small that there is only one city that is responsible for the production of daily goods, and uses the road network to transport the goods to the capital. Ikki finds that the biggest problem in the country is that transportation speed is too slow.
Since Ikki was an ACM/ICPC contestant before, he realized that this, indeed, is a maximum flow problem. He coded a maximum flow program and found the answer. Not satisfied with the current status of the transportation speed, he wants to increase the transportation ability of the nation. The method is relatively simple, Ikki will reconstruct some roads in this transportation network, to make those roads afford higher capacity in transportation. But unfortunately, the country of Phoenix is not so rich in GDP that there is only enough money to rebuild one road. Ikki wants to find such roads that if reconstructed, the total capacity of transportation will increase.
He thought this problem for a loooong time but cannot get it. So he gave this problem to frkstyc, who put it in this POJ Monthly contest for you to solve. Can you solve it for Ikki?
Input
The input contains exactly one test case.
The first line of the test case contains two integers N, M (N ≤ 500, M ≤ 5,000) which represents the number of cities and roads in the country, Phoenix, respectively.
M lines follow, each line contains three integers a, b, c, which means that there is a road from city a to city b with a transportation capacity of c (0 ≤ a, b < n, c ≤ 100). All the roads are directed.
Cities are numbered from 0 to n − 1, the city which can product goods is numbered 0, and the capital is numbered n − 1.
Output
You should output one line consisting of only one integer K, denoting that there are K roads, reconstructing each of which will increase the network transportation capacity.
Sample Input
Sample Output
Time Limit: 2000MS | Memory Limit: 131072K | |
Total Submissions: 7491 | Accepted: 2172 |
Ikki is the king of a small country – Phoenix, Phoenix is so small that there is only one city that is responsible for the production of daily goods, and uses the road network to transport the goods to the capital. Ikki finds that the biggest problem in the country is that transportation speed is too slow.
Since Ikki was an ACM/ICPC contestant before, he realized that this, indeed, is a maximum flow problem. He coded a maximum flow program and found the answer. Not satisfied with the current status of the transportation speed, he wants to increase the transportation ability of the nation. The method is relatively simple, Ikki will reconstruct some roads in this transportation network, to make those roads afford higher capacity in transportation. But unfortunately, the country of Phoenix is not so rich in GDP that there is only enough money to rebuild one road. Ikki wants to find such roads that if reconstructed, the total capacity of transportation will increase.
He thought this problem for a loooong time but cannot get it. So he gave this problem to frkstyc, who put it in this POJ Monthly contest for you to solve. Can you solve it for Ikki?
Input
The input contains exactly one test case.
The first line of the test case contains two integers N, M (N ≤ 500, M ≤ 5,000) which represents the number of cities and roads in the country, Phoenix, respectively.
M lines follow, each line contains three integers a, b, c, which means that there is a road from city a to city b with a transportation capacity of c (0 ≤ a, b < n, c ≤ 100). All the roads are directed.
Cities are numbered from 0 to n − 1, the city which can product goods is numbered 0, and the capital is numbered n − 1.
Output
You should output one line consisting of only one integer K, denoting that there are K roads, reconstructing each of which will increase the network transportation capacity.
Sample Input
2 1 0 1 1
Sample Output
1 题意:从源点0到汇点n-1,问给那些边增加容量会增大整个网络的容量??输出边的数量。 这里有个重要的概念:关键边,关键边定义为 :通过增加某个边的容量使得网络的最大流增加 个人的理解为最小割里面的边一定是关键割边,但关键割边不一定是最小割。 这题的做法是先求一次最大流,然后对残余网络进行两次DFS,从源点的DFS很简单,从正向边搜到边的容量为0即可,得到点集A,标记;主要是从汇点进行第二次DFS,这里就要用到技巧了,网络流有个神奇的反向边,我们从反向边进行DFS(也要判断一下正向边是否为0)得到点集B,标记;然后遍历所有的边,如果某条边的两个端点分别属于点集 A,B,那么这条边肯定就是关键割边,记录之。
#include <stdio.h> #include <algorithm> #include <queue> #include <string.h> #include <math.h> #include <iostream> #include <math.h> using namespace std; const int N = 505; const int INF = 999999999; struct Edge { int v,next; int w; } edge[N*N]; int head ; int level ; int tot; void init() { memset(head,-1,sizeof(head)); tot=0; } void addEdge(int u,int v,int w,int &k) { edge[k].v = v,edge[k].w=w,edge[k].next=head[u],head[u]=k++; edge[k].v = u,edge[k].w=0,edge[k].next=head[v],head[v]=k++; } int BFS(int src,int des) { queue<int >q; memset(level,0,sizeof(level)); level[src]=1; q.push(src); while(!q.empty()) { int u = q.front(); q.pop(); if(u==des) return 1; for(int k = head[u]; k!=-1; k=edge[k].next) { int v = edge[k].v; int w = edge[k].w; if(level[v]==0&&w!=0) { level[v]=level[u]+1; q.push(v); } } } return -1; } int dfs(int u,int des,int increaseRoad) { if(u==des) return increaseRoad; int ret=0; for(int k=head[u]; k!=-1; k=edge[k].next) { int v = edge[k].v; int w = edge[k].w; if(level[v]==level[u]+1&&w!=0) { int MIN = min(increaseRoad-ret,w); w = dfs(v,des,MIN); if(w>0) { edge[k].w -=w; edge[k^1].w+=w; ret+=w; if(ret==increaseRoad) return ret; } else level[v] = -1; } } return ret; } int Dinic(int src,int des) { int ans = 0; while(BFS(src,des)!=-1) ans+=dfs(src,des,INF); return ans; } int vis ; void dfs0(int u) { vis[u] = 1; for(int k=head[u]; k!=-1; k=edge[k].next) { int v = edge[k].v,w = edge[k].w; if(!vis[v]&&w>0) { dfs0(v); } } } void dfs1(int u) { vis[u] = 2; for(int k=head[u]; k!=-1; k=edge[k].next) { int v = edge[k].v; if(!vis[v]&&edge[k^1].w>0&&edge[k].w>0) ///汇点利用反向边进行搜索,这里还要判断一下正向边是否大于0 { dfs1(v); } } } int main() { int n,m; scanf("%d%d",&n,&m); init(); for(int i=0; i<m; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); if(u==v) continue; addEdge(u,v,w,tot); } memset(vis,0,sizeof(vis)); Dinic(0,n-1); dfs0(0); dfs1(n-1); int ans = 0; for(int u=0; u<n; u++) { for(int k=head[u]; k!=-1; k=edge[k].next) { if(k%2==1) continue; ///只考虑正向边 if(vis[u]==1&&vis[edge[k].v]==2) ans++; } } printf("%d\n",ans); }
相关文章推荐
- Windows7+VS2012下OpenGL 4的环境配置
- hdu2044 一只小蜜蜂....
- [Ruby笔记]22.Ruby :: namespace 以及 instance method 与class method
- 华为项目管理10大模板Excel版(可直接套用_非常实用)
- js-shortid:优雅简洁地实现短ID
- 阿里云Hadoop开发自动打包上传运行maven的pom.xml
- c++作业7
- 第116课: Spark Streaming性能优化:如何在毫秒内处理处理大吞吐量的和数据波动比较大 的程序
- Android Studio常用快捷键、Android Studio快捷键大全
- 浪潮之巅 科技之巅
- 个人最终总结
- storm集群搭建
- https相关原理
- 查找两个数组的公共元素
- 观察者模式
- linux socket 编程
- 读软件工程的职业道德有感
- 由linux命令行下的两条命令来阐释输出结果和返回值的区别
- iOS的动画效果类型及实现方法
- 华为项目管理10大模板Excel版(可直接套用_非常实用)