Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2266 | Accepted: 715 |
Description
No.1 station and No. n station can't be destroyed because of the heavy guard. Of course there is no road from No.1 station to No. n station.
Please help Gabiluso to calculate the minimum number of bus stations he must destroy to complete his mission.
Input
For each test case:
The first line contains 3 integers, n, m and k. (0 < n <= 50,0 < m <= 4000, 0 < k < 1000)
Then m lines follows. Each line contains 2 integers, s and f, indicating that there is a road from station No. s to station No. f.
Output
Sample Input
5 7 3
1 3
3 4
4 5
1 2
2 5
1 4
4 5
0 0 0
Sample Output
2
Source
题目大意:
有n个点,m条无向边,问最少去掉多少个点,能够使得从1到n的最短路的距离大于K,不能去掉点1和点n。
思路:
1、首先我们考虑这样一个问题,如果我们不考虑这个限制K,问题就变成了这样:有n个点,m条无向边,问最少去掉多少个点,能够使得没有从1到n的路径。
那么应对这个问题相对而言就简单很多了:
①将每个点都一分为二,并在其间建立一条流为1的边。表示这个点去除需要1的花费。
②因为不能去掉点1和点n,那么我们在上述拆点过程中,在1和1的拆点之间的流从1增加到INF,同理点n也一样。
③然后将所有有向边加入网络中,如果有边(u,v),那么对应建立一条有向边:u拆点-------->v,流设定为INF。
那么对应建好图之后跑一遍最大流,得到的也就是最小割,就能够解决这个问题。
2、那么这时候我们再加上这个限制K.并且考虑这样一个问题:
①如果不考虑限制K,跑最大流其实也相当于跑费用流,当前持续增广时候,增广出的一条路径的值为当前从1到n最短路径值,然后无论最短路值为多少,因为是想要阻断从1到n的所有路径,那么对应加上这条路的瓶颈边的流之后,就相当于阻断了这条路径。
②那么加上限制K,其实也是在跑费用流,当前持续增广的时候,增广出的一条路径的值为当前从1到n最短路径值,然后这个时候我们考虑最短路径值为多少,如果大于K,明显当前网络中没有从1到n小于等于K的最短路径可走了,那么此时就可以停止算法,那么如果这条最短路径值小于等于K,那么对应加上这条路的瓶颈边的流之后,就相当于去掉了当前这条从1到n的最短路径值小于等于K的路径了。
那么我们在建图的时候和上述过程差不太多:
①将每个点都一分为二,并在其间建立一条流为1的边,花费为0。表示这个点去除需要1的花费。
②因为不能去掉点1和点n,那么我们在上述拆点过程中,在1和1的拆点之间的流从1增加到INF,同理点n也一样。
③然后将所有有向边加入网络中,如果有边(u,v),那么对应建立一条有向边:u拆点-------->v,流设定为INF,花费为1(边权为1)。
那么对应建好图之后跑持续增广算法即可。
3、注意此题可不是最大流条件下的最小费用。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
struct node
{
int from;
int to;
int w;
int f;
int num;
int next;
}e[400000];
int head[10000];
int vis[10000];
int dis[10000];
int pre[10000];
int path[10000];
int n,m,kk,cont,ss,tt;
void add(int from,int to,int f,int w)
{
e[cont].to=to;
e[cont].f=f;
e[cont].w=w;
e[cont].num=cont;
e[cont].next=head[from];
head[from]=cont++;
}
void Getmap()
{
ss=n*2+1;
tt=ss+1;
cont=0;
memset(head,-1,sizeof(head));
add(ss,1,0x3f3f3f3f,0);
add(1,ss,0,0);
add(n*2,tt,0x3f3f3f3f,0);
add(tt,n*2,0,0);
for(int i=1;i<=n;i++)
{
if(i==1||i==n)
{
add(i,i+n,0x3f3f3f3f,0);
add(i+n,i,0,0);
continue;
}
add(i,i+n,1,0);
add(i+n,i,0,0);
}
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x+n,y,0x3f3f3f3f,1);
add(y,x+n,0,-1);
}
}
int SPFA()
{
for(int i=1;i<=tt;i++)dis[i]=0x3f3f3f3f;
memset(vis,0,sizeof(vis));
dis[ss]=0;
queue<int >s;s.push(ss);
while(!s.empty())
{
int u=s.front();
s.pop();vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int f=e[i].f;
int w=e[i].w;
if(f&&dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
pre[v]=u;
path[v]=e[i].num;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
if(dis[tt]<=kk)return 1;
else return 0;
}
void MCMF()
{
int maxflow=0;
while(SPFA()==1)
{
int minn=0x3f3f3f3f;
for(int i=tt;i!=ss;i=pre[i])
{
minn=min(minn,e[path[i]].f);
}
for(int i=tt;i!=ss;i=pre[i])
{
e[path[i]].f-=minn;
e[path[i]^1].f+=minn;
}
maxflow+=minn;
}
printf("%d\n",maxflow);
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&kk))
{
if(n==0&&m==0&&kk==0)break;
Getmap();
MCMF();
}
return 0;
}