【最小割】【图的点连通度】破坏图

本文探讨了图论中的最小割问题和点连通度的概念。通过具体的题目描述,阐述如何破坏图的连通性。题目提供输入、输出格式以及样例,并给出了数据范围。100%的数据规模限制为n不超过200,边数m不超过10000,而k的取值在2到n之间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目描述】

一个图有n个点,m条边(有向边),要从起点1到终点n。破坏中间的一些点,使得从起点
到终点经过的边数必须大于k条。求最少要破坏多少个点。
起点和终点是不能被破坏的。数据保证不存在起点到终点的边。
注:起点和终点不连通视为距离无穷大。

【输入】

第一行读入三个正整数n,m,k。n表示点的个数,m表示边的条数,k表示从起点到终点经过
的边数必须大于k条。
接下来m行,每行读入两个数x和y,表示有一条x到y的边。

【输出】

输出答案。

【样例输入】

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

【样例输出】

2

【数据范围】

对于20%的数据,1 <= n <= 15, 1 <= m <= 100,2 <= k <= n

对于100%的数据,1 <= n <= 200, 1 <= m <= 10000, 2 <= k <= n


【题解】

以下摘自:http://www.cnblogs.com/wally/archive/2013/08/26/3282974.html

图的连通度问题是指:在图中删去部分元素(点或边),使得图中指定的两个点s和t不连通 (不存在从s到t的路径),求至少要删去几个元素。 
图的连通度分为点连通度和边连通度: 
(1)点连通度:只许删点,求至少要删掉几个点(当然,s和t不能删去,这里保证原图中至少有三个点); 
(2)边连通度:只许删边,求至少要删掉几条边。 


求法:
【1】有向图的边连通度: 
这个其实就是最小割问题。以s为源点,t为汇点建立网络,原图中的每条边在网络中仍存在,容量为1,求该网络的最小割(也就是最大流)的值即为原图的边连通度。 
【2】有向图的点连通度: 
需要拆点。建立一个网络,原图中的每个点i在网络中拆成i'与i'',有一条边<i', i''>,容量为1 (<s', s''>和<t', t''>例外,容量为正无穷)。原图中的每条边<i, j>在网络中为边<i'', j'>, 
容量为正无穷。以s'为源点、t''为汇点求最大流,最大流的值即为原图的点连通度。 
说明:最大流对应的是最小割。显然,容量为正无穷的边不可能通过最小割,也就是原图中的边和s、t两个点不能删去;若边<i, i''>通过最小割,则表示将原图中的点i删去。
【3】无向图的边连通度: 
将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【1】)处理; 
【4】无向图的点连通度: 
将图中的每条边(i, j)拆成<i, j>和<j, i>两条边,再按照有向图的办法(【2】)处理。

然后很明显这道题就是求节点1到节点N的点连通度了。。当然首先我们要把合法的路径(总路程大于K)的删了 用floyd搞定 然后就是上面的模型了 这题基本就是练代码了……


#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

int read()
{
	int sign = 1, n = 0; char c = getchar();
	while(c < '0' || c > '9'){ if(c == '-') sign = -1; c = getchar(); }
	while(c >= '0' && c <= '9') { n = n*10 + c-'0'; c = getchar(); }
	return sign*n;
}

const int inf = 0x3f3f3f3f;

int N, M, K;
int map[205][205];
int u[10005], v[10005]; 

inline void floyd()
{
	for(int i = 1; i <= N; ++i)
	for(int j = 1; j <= N; ++j)
		if(i ^ j && !map[i][j]) map[i][j] = inf;
	for(int k = 1; k <= N; ++k)
	for(int i = 1; i <= N; ++i)
	for(int j = 1; j <= N; ++j)
		map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
}

struct ed{
	int v, flow, next;
}e[20005 + 405];
int k = 2, head[405], cur[405], dis[405];
int S, T;

inline void adde(int u, int v, int flow)
{
	e[k] = (ed){ v, flow, head[u] };
	head[u] = k++;
	e[k] = (ed){ u, 0, head[v] };
	head[v] = k++;
}

inline int in(int x) { return x; }
inline int out(int x) { return x + N; }

queue <int> q;

bool bfs()
{
	memset(dis, -1, sizeof(dis));
	memcpy(cur, head, sizeof(cur));
	while(q.size()) q.pop();
	q.push(S); dis[S] = 0;
	
	while(q.size())
	{
		int u = q.front(); q.pop();
		for(int i = head[u]; i; i = e[i].next)
		{
			int v = e[i].v;
			if(e[i].flow && dis[v] == -1)
			{
				dis[v] = dis[u] + 1;
				if(v == T) return true;
				q.push(v);
			}
		}
	}
	
	return false;
}

int dfs(int u, int maxf)
{
	 if(u == T || !maxf) return maxf;
	 
	 int flow = 0, f;
	 for(int &i = cur[u]; i; i = e[i].next)
	 {
	 	int v = e[i].v;
	 	if(dis[v] == dis[u] + 1 && (f = dfs(v, min(maxf, e[i].flow))) > 0)
	 	{
	 		flow += f; maxf -= f;
	 		e[i].flow -= f; e[i ^ 1].flow += f;
	 		if(!maxf) break;
	 	}
	 }
	 
	 return flow;
}

inline int max_flow()
{
	int f = 0; S = out(1), T = in(N);
	while(bfs()) f += dfs(S, inf);
	return f;
}

int main()
{
	freopen("A.in", "r", stdin);
	freopen("A.out", "w", stdout);
	
	N = read(), M = read(), K = read();
	for(int i = 1; i <= M; ++i) 
	{
		u[i] = read(), v[i] = read();
		map[u[i]][v[i]] = 1;
	}
	floyd();
	for(int i = 2; i < N; ++i) adde(in(i), out(i), 1);
	for(int i = 1; i <= M; ++i) 
		if(map[1][u[i]] + map[v[i]][N] + 1 <= K) adde(out(u[i]), in(v[i]), inf);
	
	printf("%d\n", max_flow());
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值