【题目描述】
一个图有n个点,m条边(有向边),要从起点1到终点n。破坏中间的一些点,使得从起点到终点经过的边数必须大于k条。求最少要破坏多少个点。
起点和终点是不能被破坏的。数据保证不存在起点到终点的边。
注:起点和终点不连通视为距离无穷大。
【输入】
第一行读入三个正整数n,m,k。n表示点的个数,m表示边的条数,k表示从起点到终点经过的边数必须大于k条。
接下来m行,每行读入两个数x和y,表示有一条x到y的边。
【输出】
输出答案。【样例输入】
5 7 31 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不能删去,这里保证原图中至少有三个点);
(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】)处理。
这个其实就是最小割问题。以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;
}