摧毁车站 | ||||||
| ||||||
Description | ||||||
Gabiluso是他国家最厉害的间谍之一。现在他试图去完成一个“不可能”的任务-减缓Colugu市的军队抵达机场的速度。Colugu市有n个车站和m条路。每条路直接连接两个车站,所有的路都是单向的。为了维护空气质量,政府停用了所有军队车辆。所以军队必须乘坐巴士去机场。两个车站之间可能不只一条路。如果一个车站被摧毁,那么所有通向那个车站的道路都没用了。Gabiluso需要去做的是摧毁一些车站使得军队不能在k分钟内赶到机场。一辆巴士通过一条路只需要一分钟。从1到n给所有车站编号。编号为1的车站在军营里,编号为n的车站在机场里。军队总是从编号为1的车站出发。 由于有重兵把守,所以编号为1和n的车站不能被摧毁。当然那里没有一条路直接从1号车站连接到n号车站。 请帮助Gabiluso计算他需要摧毁车站的最小数量,他必须完成任务。 | ||||||
Input | ||||||
有多组测试数据。当输入三个0时,输入停止。 对于每组测试数据: 第一行包含三个整数,n,m 和 k。 (0 < n <= 50,0 < m <= 4000, 0 < k < 1000); 紧接着有m行,每行包含两个整数 s 和 f,意思是有一条路从s号车站通往f号车站。 | ||||||
Output | ||||||
对于每组测试数据,输出 Gabiluso 必须摧毁车站的最小数量。 | ||||||
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 |
思路:
1、首先我们确定题目解题突破点:n<=50,最开始的时候是想Dfs枚举所有拆点情况,维护最小拆点数,输出答案,但是毕竟n最大也有50。最大枚举量达到2^50,也避免不了TLE的命运。
2、思路核心还是放在n<=50上边,最多拆了48个点,其实这个图就一定不连通了,其实也就是说,如果我们能够每一次确定拆一个点能够使得最短路的值变大或者是拆一条最短路,那么我们最多拆48次点,就一定能够达到目的,而且题目保证有解,那么我们只要每一次锁定一个点,拆掉他,能够使得最短路值变大,或者是能够拆一条最短路,那么拆这个点就是有意义的。
3、那么这个点到底应该拆哪里的呢?毋庸置疑,如果拆的这个点不在最短路上,那么就不会影响当前图的最短路问题,那么我们记录路径,拆最短路上的点,那么我们也知道,拆最短路上的任意一点,都能使得这条最短路无效,也就达到了刚才所述的目的,拆掉最短路上任意一点,能够使得最短路值变大,或者是能够拆一条最短路。
4、既然确定到了这里,思路就已经定型了:
①求一遍最短路,并且记录路径,因为点边都比较少,用哪一种都可以。
②判断一下最短路值,如果大于k,跳出算法。否则跳③
③拆一个最短路上的点,跳①。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int tmp[55][55];
int pre[55][55];
int vis[55];
int map[55][55];
int main()
{
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k))
{
if(n==0&&m==0&&k==0)break;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
map[i][j]=0x3f3f3f3f;
tmp[i][j]=0x3f3f3f3f;
pre[i][j]=i;
}
}
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
map[x][y]=1;
tmp[x][y]=1;
}
memset(vis,0,sizeof(vis));
int cont=0;
while(1)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
map[i][j]=tmp[i][j];
pre[i][j]=i;
}
}
for(int i=1;i<=n;i++)
{
if(vis[i]==1)continue;
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
if(map[j][k]>map[j][i]+map[i][k])
{
map[j][k]=map[j][i]+map[i][k];
pre[j][k]=pre[i][k];
}
}
}
}
if(map[1][n]>k)break;
if(vis[pre[1][n]]!=1)
vis[pre[1][n]]=1;
cont++;
}
printf("%d\n",cont);
}
}