导弹防御塔

导弹有:发射时间/冷却时间/到达时间 给定若干个防御塔和目标 问最少多少时间能够消灭所有敌人

最多最少问题先看看二分答案!!!
二分答案之后 根据二分的时间 可以确定每个塔的匹配数
二分图匹配要求每个点都是等价的 因此这道题只能用拆点来做

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

const int N=55;
const double eps=1e-9;
int read()
{
	int x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}
//二分图由于是认为的分成了两个集合 左右集合所以点的编号可以重复 
struct Edge
{
	int to,next;
}e[N*N*N];//No3: the number of left:n*n the number of right: n  so we need n^3 edges
int head[N*N*2],cnt,num;
void add(int a,int b){ e[++cnt]=(Edge){b,head[a]};head[a]=cnt;}
double dis[N][N];
int X1[N],Y1[N],X2[N],Y2[N];
double getdis(int x,int y,int _x,int _y){return sqrt((x-_x)*(x-_x)+(y-_y)*(y-_y));}
int n,m,t2,v; double t1;
bool vis[N];
int match[N];

bool dfs(int x)
{	
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(vis[y]) continue; vis[y]=1;

		if(!match[y]|| dfs(match[y]) ){ match[y]=x; return true;}
	}
	return false;
}


//mid can be very large so we can not enumerate time
//upper bound: each defensive tower launch m missile
bool check(double mid)
{
	memset(head,0,sizeof head); cnt=0; num=0;
	memset(match,0,sizeof match);//No1: clear match array
	for(int i=1;i<=n;i++)//enumerate each defensive tower
	{
		for(int j=1;j<=m;j++)//enumerate each missle
		{
			double t=(j-1)*(t1+t2)+t1;
			if(t>mid) break;
			bool flag=1;
			for(int k=1;k<=m;k++)
				if( (mid-t)*v>=dis[i][k]) 
				{
					if(flag) num++,flag=0;//No2: strict correspondence
					add(num,k);
				}
		}
	}
	int ans=0;
	for(int i=1;i<=num;i++)
	{
		memset(vis,0,sizeof vis);
		ans+=dfs(i);
	}
	return ans>=m;
}

int main()
{	
	n=read();m=read();t1=read()*1.0/60;t2=read();v=read();
	for(int i=1;i<=m;i++) X2[i]=read(),Y2[i]=read();
	for(int i=1;i<=n;i++) X1[i]=read(),Y1[i]=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		 dis[i][j]=getdis(X1[i],Y1[i],X2[j],Y2[j]);

	double l=0,r=1e6;
	while(r-l>eps)
	{
		double mid=(l+r)/2;
		if(check(mid)) r=mid;
		else l=mid;
	}
	
	printf("%.6lf",r);

}

注意:
1.二分图两边编号可以重复 但是只能加从左向右的单向边
2.eps要设置到1e-9才能够满足1e-6的精度要求
3. 边和点的空间一定要开的足够的大

posted @ 2022-02-10 21:12  __iostream  阅读(35)  评论(0)    收藏  举报