Time Limit: 2000MS | Memory Limit: 131072K | |
Total Submissions: 6106 | Accepted: 1729 |
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
Sample Input
2 1
0 1 1
Sample Output
1
求有多少条割边。割边的意思是,求得最大流以后的残留网络中,假定某条边两个端点为s,e,满足流量为0,且源点到s的过程中流量>0,e到汇点的过程流量>0的边。其实流量为0的意思也就是满流。那么源点到s和汇点到e的流量大于0即是还未满流。对于这道题,如果能够增大s-e的容量,自然就能够继续增广了。
所以此题的做法就是跑一遍最大流,得到一个残留网络。枚举每一条边,如果该边未满流(大于0),则记录该边是连通的。然后从源点dfs找到源点可达的所有点,标记起来。然后再枚举每一条反向边,如果未满流就连通,从汇点开始dfs标记汇点可达的点。最后再枚举每一条边,如果边满流(容量为0),且源点可达该边的起点,汇点可达该边的终点,则这条边就是割边,统计全部这样的边就是答案。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #define SIZE 512 #define inf 0xfffffff using namespace std; struct node { int to,val,next; }edge[SIZE*SIZE]; int N,M,sc,sk,pt; int head[SIZE],idx; int gap[SIZE],dis[SIZE]; bool map[SIZE][SIZE],reach[SIZE],antiReach[SIZE]; void addnode(int from,int to,int val) { edge[idx].to = to; edge[idx].val = val; edge[idx].next = head[from]; head[from] = idx ++; edge[idx].to = from; edge[idx].val = 0; edge[idx].next = head[to]; head[to] = idx ++; } int dfs(int cur,int cval) { if(cur == sk) return cval; int mindis = pt - 1, tval = cval; for(int i=head[cur]; i!=-1; i=edge[i].next) { int to = edge[i].to; if(edge[i].val > 0) { if(dis[to] + 1 == dis[cur]) { int val = dfs(to,min(edge[i].val,tval)); tval -= val; edge[i].val -= val; edge[i^1].val += val; if(dis[sc] >= pt) return cval - tval; if(!tval) break; } if(dis[to] < mindis) mindis = dis[to]; } } if(cval == tval) { --gap[dis[cur]]; if(!gap[dis[cur]]) dis[sc] = pt; dis[cur] = mindis + 1; ++gap[dis[cur]]; } return cval - tval; } void sap() { memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); gap[sc] = pt; int ret = 0; while(dis[sc] < pt) ret += dfs(sc,inf); } void read() { sc = 0, sk = N-1, pt = sk+1; idx = 0; memset(head,-1,sizeof(head)); int s,e,v; for(int i=1; i<=M; i++) { scanf("%d%d%d",&s,&e,&v); addnode(s,e,v); } } void dfs_reach(int v) { reach[v] = true; for(int i=0; i<N; i++) if(!reach[i] && map[v][i]) dfs_reach(i); } void dfs_antiReach(int v) { antiReach[v] = true; for(int i=0; i<N; i++) if(!antiReach[i] && map[v][i]) dfs_antiReach(i); } void work() { memset(reach,0,sizeof(reach)); memset(antiReach,0,sizeof(antiReach)); memset(map,0,sizeof(map)); for(int i=0; i<idx; i+=2) //枚举源点未满流的边,记录正向边。其中edge[i^1].to = from; if(edge[i].val != 0) map[edge[i^1].to][edge[i].to] = true; dfs_reach(0); memset(map,0,sizeof(map)); for(int i=0; i<idx; i+=2) //记录反向边 if(edge[i].val != 0) map[edge[i].to][edge[i^1].to] = true; dfs_antiReach(N-1); int ans = 0; for(int i=0; i<idx; i+=2) if(edge[i].val == 0 && reach[edge[i^1].to] && antiReach[edge[i].to]) ans ++; printf("%d\n",ans); } int main() { scanf("%d%d",&N,&M); read(); sap(); work(); return 0; }