HDU - 6214 Smallest Minimum Cut (求最少边数的最小割的边数)

版权声明:本文为博主原创文章,转载请附上注明就行_(:з」∠)_。 https://blog.csdn.net/vocaloid01/article/details/82688420

Time limit 2000 ms ,Memory limit 32768 kB

Consider a network G=(V,E) with source s and sink t. An s-t cut is a partition of nodes set V into two parts such that s and t belong to different parts. The cut set is the subset of E

with all edges connecting nodes in different parts. A minimum cut is the one whose cut set has the minimum summation of capacities. The size of a cut is the number of edges in the cut set. Please calculate the smallest size of all minimum cuts.

Input

The input contains several test cases and the first line is the total number of cases T (1≤T≤300).
Each case describes a network G, and the first line contains two integers n (2≤n≤200) and m (0≤m≤1000) indicating the sizes of nodes and edges. All nodes in the network are labelled from 1 to n.
The second line contains two different integers s and t (1≤s,t≤n) corresponding to the source and sink.
Each of the next m lines contains three integers u,v and w (1≤w≤255) describing a directed edge from node u to v with capacity w.

Output

For each test case, output the smallest size of all minimum cuts in a line.

Sample Input

2
4 5
1 4
1 2 3
1 3 1
2 3 1
2 4 1
3 4 2
4 5
1 4
1 2 3
1 3 1
2 3 1
2 4 1
3 4 3

Sample Output

2
3

分析:

1,在原图最小割不唯一的前提下,第一次求出的最小割的边数未必是最少的。在割边集的边权和相等的前提下,可能存在一个边数更少的最小割。

2,不管有多少个最小割,我们在原图跑一次最大流之后,残量网络里面满流的边一定是属于某个或多个最小割的,相应的没有满流的边一定不属于任何一个最小割。

3,这样问题就变成——在所有满流的边中破坏最少的边数来阻断0到N-1的路径,类似在最短路的边中破坏最少的边来阻断起点到终点的路径,只是多了对非最短路边(在本题中是非满流边)的处理。

做法:

边权 * 一个大数再%那个大数是0,你+1的话,如果这是条满流边的话,%那个大数是1,设最小割的最少边数是x,那么流量%那个大数 == x。

其他与最大流无异。

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>

using namespace std;

const int MAXN = 205;
const int INF = 0x3f3f3f3f;
 
struct Edge{
	int flow,to,rev;
	Edge(){}
	Edge(int a,int b,int c):to(a),flow(b),rev(c){}
};
 
vector<Edge> E[MAXN];
 
inline void Add(int from,int to,int flow){
	E[from].push_back(Edge(to,flow,E[to].size()));
	E[to].push_back(Edge(from,0,E[from].size()-1));
}
 
int deep[MAXN];
 
bool BFS(int from,int to){
	memset(deep,-1,sizeof deep);
	deep[from] = 0;
	queue<int> Q;
	Q.push(from);
	while(!Q.empty()){
		int t = Q.front();
		Q.pop();
		for(int i=0 ; i<E[t].size() ; ++i){
			Edge& e = E[t][i];
			if(e.flow > 0 && deep[e.to] == -1){
				deep[e.to] = deep[t] + 1;
				Q.push(e.to);
			}
		}
	}
	return deep[to] != -1;
}
 
int iter[MAXN];
 
int DFS(int from,int to,int flow){
	if(from == to || flow == 0)return flow;
	for(int &i=iter[from] ; i<E[from].size() ; ++i){
		Edge &e = E[from][i];
		if(e.flow > 0 && deep[e.to] == deep[from]+1){
			int nowflow = DFS(e.to,to,min(flow,e.flow));
			if(nowflow > 0){
				e.flow -= nowflow;
				E[e.to][e.rev].flow += nowflow;
				return nowflow;
			}
		}
	}
	return 0;
}
 
int Dinic(int from,int to){
	int sumflow = 0;
	while(BFS(from,to)){
		memset(iter,0,sizeof iter);
		int t;
		while((t=DFS(from,to,INF)) > 0)sumflow += t;
	}
	return sumflow;
}

int main(){
	
	int T,n,m,s,t;
	scanf("%d",&T);
	while(T--){
		scanf("%d %d %d %d",&n,&m,&s,&t);
		for(int i=1 ; i<=m ; ++i){
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			Add(a,b,c*(m+1)+1); /*其实乘的那个数是几无所谓
			但是要注意考虑会不会出现%结果是1的边数大于乘的那个数。
			而乘(边数+1)则可以防止这个问题。*/ 
		}
		printf("%d\n",Dinic(s,t)%(m+1));
		for(int i=0 ; i<=n ; ++i)E[i].clear();
	}
	
	return 0;
}
 

猜你喜欢

转载自blog.csdn.net/vocaloid01/article/details/82688420