【Floyed】【匈牙利算法】导弹(jzoj 1610)

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/ssllyf/article/details/86635968

导弹

题目大意:

有n个城市,有一部分是A国的,有一部分是B国的(小于A国的),A国每个城市都有一枚导弹(只有一枚),炸毁别的城市的时间是到这个城市的距离,请问A国最快要多久可以炸毁B国所有城市

样例输入

3

0 2 1

2 0 10

1 10 0

1

2

1

3

样例输出

3

数据范围限制

各城市距离<=100

城市数<=100

解题思路:

先用Floyed来求出最短路,然后二分枚举答案再用匈牙利算法确认是否可以,即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int bg[105],head[105],a[105][105],b[105],c[105],w,sum,l,r,mid,n,m,nm;
bool pd[105];
struct rec
{
	int to,next;
}f[10005];//每一条路线
bool js(int xx)
{
	int l=0;
	for (int i=head[xx];i;i=f[i].next)//连接此点的每一条线
	  if (!pd[f[i].to])//可以抢
	  {
	  	l=bg[f[i].to];//之前是谁打的
	  	bg[f[i].to]=xx;//代替
	  	pd[f[i].to]=true;//不能抢了
	  	if ((!l)||(js(l))) return true;//之前没人或抢到了
	  	bg[f[i].to]=l;//没法打这个城市就还给之前的
	  }
	return false;//找不到可以打的
}
bool sj(int now)
{
	memset(head,0,sizeof(head));//清零
	memset(bg,0,sizeof(bg));//清零
	w=0;//清零
	sum=0;//清零
	for (int i=1;i<=n;i++)
	  for (int j=1;j<=m;j++)
	    if (a[b[i]][c[j]]<=now)//判断是否少于当前的时间
		  {
		  	f[++w].to=j;//下一个点
		  	f[w].next=head[i];//下一条线
		  	head[i]=w;//这个点的第一条线
		  } 
	for (int i=1;i<=n;i++)
	{
		memset(pd,false,sizeof(pd));//清零
		if (js(i)) sum++;//判断是否能打到敌人
	}
	return sum==m;//判断是否打完
}
int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d",&nm);
	for (int i=1;i<=nm;i++)
	  for (int j=1;j<=nm;j++)
	    scanf("%d",&a[i][j]);
	for (int k=1;k<=nm;k++)
	  for (int i=1;i<=nm;i++)
	    for (int j=1;j<=nm;j++)
	      if ((i!=j)&&(j!=k)&&(k!=i)&&(a[i][k]+a[k][j]<a[i][j]))
	        a[i][j]=a[i][k]+a[k][j];//Floyed
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	  scanf("%d",&b[i]);
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
	  scanf("%d",&c[i]);
	l=1;
	r=10000;
	while(l<=r)
	{
		mid=(l+r)/2;//二分答案
		if (sj(mid)) r=mid-1;
		else l=mid+1;
	}
	printf("%d",l);//输出
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ssllyf/article/details/86635968