导弹

Description

给出一张无向的完全图(任意两点之间都有一条边的图)\(G=(V,E)\),它可以表示出某一块大陆的地图:每个顶点表示一座城市,每条边代表连接的两个城市间的距离,该大陆任两个城市都是直接连通的。另外在这个大陆上有两个特殊的国家,我们称为\(A\)国与\(B\)国,其中\(A\)国有\(N\)个城市,\(B\)国有\(M\)个城市。
这里\(A\)国相对于\(B\)国来说是一个大国(我们有\(N>=M\)),而且它最近发明了一种新型武器:响尾蛇导弹\((A\ Crotalid\ Missile)\),这种武器威力十分巨大,以至于每枚导弹都可以摧毁任意一座城市。\(A\)国总统在战略安排上要求\(A\)国管辖的每个城市都配备一枚这种响尾蛇导弹。\(B\)国窃取到了这个情报,\(B\)国总统当然不能坐以待毙,他感觉受到了强大的威胁,于是要求他们的科学家们尽快研制出一个导弹防御系统来抵御将来可能遭受的攻击。当然这个防御系统必须是可靠且有效的,因此在制造系统之前\(B\)国的科学家们必须首先考虑清楚该系统的反应速度如何确定。所以作为\(B\)国最聪明科学家之一的你,必须尽快算出\(A\)国要摧毁\(B\)国所有城市至少需要的时间是多少。

Input

输入第一行为一个整数\(K\),表示这块大陆的顶点数。接下来\(K\)行,每行包含\(K\)个整数,描述了城市的连接情况。这个\(K*K\)的矩阵中,\(matrix[i][j]\)表示城市\(i\)到城市j的距离,这也是导弹由城市\(i\)到城市\(j\)间的飞行时间。这里有:\(matrix[i][j]=matrix[j][i],matrix[i][i]=0,1<=matrix[i][j]<=100\)
接下来一行为整数\(N\)\(1<=N<=K\),为\(A\)国的城市数。下面一行\(N\)个整数,列出\(A\)国管辖的城市编号。
再下来一行为整数\(M\)\(1<=M<=N\),为\(B\)国的城市数。下面一行\(M\)个整数,列出\(B\)国管辖的城市编号。
\(A\)国与\(B\)国管辖的所有城市编号均不相同。

Output

输出文件只有一行,为导弹摧毁\(B\)国所有城市至少所需要的时间。

Sample

Sample Input

  3
  0 2 1
  2 0 10
  1 10 0
  1
  2
  1
  3

Sample Output

  3

Hint

本题共\(8\)个数据点,数据点与\(K\)大小对应关系:
1:K=2;
2:K=5;
3:K=10;
4:K=25;
5:K=46;
6:K=72;
7,8:K=100;

Train of Thought

数据比较小
可以直接先用DP求出最短路
因为导弹可以同时发射
所以只需要将\(A\)国的城市和\(B\)国的城市一一对应
然后取所花时间的最大值就行了
所以我们可以二分答案
那怎么一一对应呢
我们就可以用匈牙利算法
不懂的可以去看看(匈牙利算法)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int h[105], la[105], F[105][105], Bol[105], l[105], r[105];
int n, m, t;
struct wh_
{
	int w, h;
}wh[10005];

void hw(int x, int y)
{wh[++t] = (wh_){y, h[x]}, h[x] = t;} 

bool Hun(int k)
{
	for(int i = h[k]; i; i = wh[i].h)
		if(!Bol[wh[i].w])
		{
			int l = la[wh[i].w];
			la[wh[i].w] = k;
			Bol[wh[i].w] = 1;
			if(!l || Hun(l))return 1;
			la[wh[i].w] = l;
		}
	return 0;
}

int Check(int k)
{
	memset(la, 0, sizeof(la));
	memset(wh, 0, sizeof(wh));
	memset(h, 0, sizeof(h));
	int Ans = 0; t = 0;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			if(F[l[i]][r[j]] <= k)
				hw(i, j);//建图
	for(int i = 1; i <= n; ++i)
	{
		memset(Bol, 0, sizeof(Bol));
		if(Hun(i))Ans++;//判断是否可以一一对应|匈牙利算法
	}
	return Ans == m;
}

int main()
{
	memset(F, 0x7f, sizeof(F));
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			scanf("%d", &F[i][j]);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			for(int k = 1; k <= n; ++k)
				F[i][j] = min(F[i][j], F[i][k] + F[k][j]);//DP最短路
	scanf("%d", &n);
	for(int i  = 1; i <= n; ++i)
		scanf("%d", &l[i]);
	scanf("%d", &m);
	for(int i  = 1; i <= m; ++i)
		scanf("%d", &r[i]);
	int left = 1, right = 1e9;
	while(left < right)//二分
	{
		int mid = (left + right) / 2;
		if(Check(mid))right = mid;
		else left = mid + 1;
	}
	printf("%d", left);
	return 0;
}
``
posted @ 2020-08-22 11:21  20Maple  阅读(211)  评论(0)    收藏  举报
Live2D