[图论]---[网络流]---最小点割数/最小点割集

最小点割数

给定一个无向图,源点S和汇点T,问最少删除几个结点能使S和T不连通。
使S和T不连通的算法我们知道有最小割,但是最小割是将边割掉,所以我们需要将求割点转化为求割边
我们知道如果在原图去掉一个结点,相当于去掉这个结点和它所连接的所有的边,所以可以将每个点拆成 入点和出点,中间连一条容量为 1 的边,如果这条边被割掉了,就相当于这个结点被删除了。S 和 T不能被删除,因此中间连接容量为INF的边。再将原图中的双向边变成容量为INF的边,求最小点割数也就变成了求 S-T 的最小割。
下面放一个模板题 “奶牛的电信”,的代码。(最后有题目链接)

#include 
#include 
#include 
#include 
#define INF 2147483647
using namespace std;
struct t_Edge {
	int next;
	int to;
	int cap;
};
t_Edge edge[10001];
int N, M, S, T, a, b;
int head[500], deep[500], num_edge;
void add(int from, int to, int cap)
{
	edge[++num_edge].next = head[from];
	edge[num_edge].to = to;
	edge[num_edge].cap = cap;
	head[from] = num_edge;
}
int bfs()
{
	memset(deep, 0, sizeof(deep));
	deep[S] = 1;
	queue q;
	q.push(S);
	while(!q.empty())
	{
		int u = q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			int v = edge[i].to;
			if(edge[i].cap>0&&!deep[v])
			{
				deep[v] = deep[u]+1;
				q.push(v);
			}
		}
	}
	return deep[T];
}
int dfs(int u, int flow)
{
	if(u==T) return flow;
	int res = 0;
	for(int i=head[u];i!=-1&&flow;i=edge[i].next)
	{
		int v = edge[i].to;
		if(edge[i].cap!=0&&deep[v]==deep[u]+1)
		{
			int newflow = dfs(v, min(flow, edge[i].cap));
			edge[i].cap -= newflow;
			edge[i^1].cap += newflow;
			flow -= newflow;
			res += newflow;
		}
	}
	return res;
}
int Dinic()
{
	int res = 0;
	while(bfs())
	    res += dfs(S, INF);
	return res;
}
int main()
{
	scanf("%d%d%d%d", &N, &M, &S, &T);
	memset(head, -1, sizeof(head));
	num_edge = -1;
	T += 100;
	for(int i=1;i<=N;i++)
	{
		if(i!=S&&i!=(T-100))
		{
			add(i, i+100, 1);
	    	add(i+100, i, 0);
		}
		else
		{
			add(i, i+100, INF);    //不能把起点和终点割掉 
			add(i+100, i, 0);
		}
	}
	for(int i=1;i<=M;i++)
	{
		scanf("%d%d", &a, &b);
		add(a+100, b, INF);
	    add(b, a+100, 0);
	    add(b+100, a, INF);
    	add(a, b+100, 0);
	}
	printf("%d\n", Dinic());
	return 0;
}

最小点割集

在求出最小点割数的基础上,如果再问:具体去掉那些顶点可以使 S-T 不连通。这就是求最小点割集。
这个问题说实话我感觉有点疑惑。
在网上可以找到一个算法就是枚举所有点,将其割掉后再跑最大流,如果最后结果比此前求得的最大流小了,证明这个点就是符合要求的点的其中一个。正确性显然。因为如果这个点符合要求,你提前把他割掉了,结果需要割掉的结点肯定就少了一个。
但是为什么疑惑呢?因为这个算法实在太简单太好理解了。所以总觉得还有更 “优美”,或者说复杂度更低的算法,但又在网上找不到。。。很迷。。。

例题链接

洛谷P1345 奶牛的电信. (求最小点割数模板题)
洛谷P2944 Earthquake Damage 2. (最小点割数 + 一点点思维)
SP300 CABLETV - Cable TV Network. (枚举 + 最小点割数)
洛谷P1344 Pollutant Control. (此题难点在第二个问,需要一定的思维)
POJ 1815. (最小点割集)

你可能感兴趣的:(图论)