题意
有一张 k k k* k k k的地图,地图上有 k k k个城市,地图上的 i , j i,j i,j表示第 i i i个城市到第 j j j个城市的距离,地图上有两个国家, A A A& B B B, A A A国有 n n n个城市,每个城市有一枚导弹, B B B国有 m m m个城市,一枚导弹能摧毁一个 B B B国的城市,求 A A A国要多久才能摧毁整个 B B B国
样例
输入
3
0 2 1
2 0 10
1 10 0
1
2
1
3
输出
3
样例解释
0 2 1
2 0 10
1 10 0
第二行第三列=10,表示编号为
2
(
A
2(A
2(A国的城市
)
)
)的城市到编号为
3
(
B
3(B
3(B国的城市
)
)
)的直接距离为
10
10
10,但这个距离并不是最优的,我们通过观察可以发现,从
A
A
A国出发(编号为
2
2
2的城市),先到编号为
1
1
1的城市(用时为
2
2
2),再从这个城市出发到
B
B
B国城市,用时为
1
1
1
所以摧毁
B
B
B国最快的时间
=
2
+
1
=
3
=2+1=3
=2+1=3
所以样例答案为
3
3
3
思路
首先通过Floyd求出最短路径,然后二分+最大匹配求出答案就OK了。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int f[505][505];
int t, N, M, K, ans;
int h[105], used[105], link[105], A[105], B[105];
struct node
{
int to, next;
}w[5005];
void add(int x, int y)
{w[++t] = (node){y, h[x]}; h[x] = t;}
bool find(int x)
{
for(int i = h[x]; i; i = w[i].next)
{
int to = w[i].to;
if (!used[to])
{
int p = link[to];
link[to] = x;
used[to] = 1;
if (!p || find(p)) return 1;
link[to] = p;
}
}
return 0;
}
bool check(int x)
{
int sum = 0;
t = 0;
memset(w, 0, sizeof(w));
memset(h, 0, sizeof(h));
memset(link, 0, sizeof(link));
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= M; ++j)
if (f[A[i]][B[j]] <= x) add(i, j);
for (int i = 1; i <= N; ++i) {
memset(used, 0, sizeof(used));
if (find(i)) sum++;
}
return sum == M;
}
int main()
{
memset(f, 0x7f, sizeof(f));
scanf("%d", &K);
for (int i = 1; i <= K; ++i)
for (int j = 1; j <= K; ++j)
scanf("%d", &f[i][j]);
for (int i = 1; i <= K; ++i)
for (int j = 1; j <= K; ++j)
for (int k = 1; k <= K; ++k)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
scanf("%d", &N);
for (int i = 1; i <= N; ++i)
scanf("%d", &A[i]);
scanf("%d", &M);
for (int i = 1; i <= M; ++i)
scanf("%d", &B[i]);
int l = 1, r = 1e6;
while (l <= r)
{
int mid = (l + r) / 2;
if (check(mid)) r = mid - 1, ans = mid;
else l = mid + 1;
}
printf("%d", ans);
return 0;
}