Description
Freda的城堡——
“Freda,城堡外发现了一些入侵者!”
“喵…刚刚探究完了城堡建设的方案数,我要歇一会儿嘛lala~”
“可是入侵者已经接近城堡了呀!”
“别担心,rainbow,你看呢,这是我刚设计的导弹防御系统的说~”
“喂…别卖萌啊……”
Freda控制着N座可以发射导弹的防御塔。每座塔都有足够数量的导弹,但是每座塔每次只能发射一枚。在发射导弹时,导弹需要T1秒才能从防御塔中射出,而在发射导弹后,发射这枚导弹的防御塔需要T2分钟来冷却。
所有导弹都有相同的匀速飞行速度V,并且会沿着距离最短的路径去打击目标。计算防御塔到目标的距离Distance时,你只需要计算水平距离,而忽略导弹飞行的高度。导弹在空中飞行的时间就是 (Distance/V) 分钟,导弹到达目标后可以立即将它击毁。
现在,给出N座导弹防御塔的坐标,M个入侵者的坐标,T1、T2和V,你需要求出至少要多少分钟才能击退所有的入侵者。
Input
第一行五个正整数N,M,T1,T2,V。
接下来M行每行两个整数,代表入侵者的坐标。
接下来N行每行两个整数,代表防御塔的坐标。
Output
输出一个实数,表示最少需要多少分钟才能击中所有的入侵者,四舍五入保留六位小数。
Sample Input
3 3 30 20 1
0 0
0 50
50 0
50 50
0 1000
1000 0
Sample Output
91.500000
Data Constraint
对于40%的数据,N,M<=20.
对于100%的数据, 1≤N≤50, 1≤M≤50,坐标绝对值不超过10000,T1,T2,V不超过2000.
思路
其实,这是一个二分图。
我们先二分答案,然后把每个防御塔拆成k个点,其中k是该防御塔在二分的时间范围内能够打击的最多次数。然后用匈牙利算法进行一次最大匹配,如果入侵者都被匹配上,缩小二分上界,否则增大二分下界
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
const int maxn=2577;
const double e=0.0000001;
vector<int> w[maxn];
double t1,tim[maxn],ans,mid;
int n,m,t2,v,f[maxn];
bool visit[maxn];
struct A
{
int x,y;
}a[maxn],b[maxn];
double dis(int x,int y)
{
int x1=b[(x/m)+(x%m!=0)].x,y1=b[(x/m)+(x%m!=0)].y,x2=a[y].x,y2=a[y].y;
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
bool match(int x)
{
if(tim[x]>mid) return 0;
for(int i=0; i<w[x].size(); i++)
{
if(!visit[w[x][i]]&&tim[x]+dis(x,w[x][i])/v<=mid)
{
visit[w[x][i]]=1;
if(!f[w[x][i]]||match(f[w[x][i]]))
{
f[w[x][i]]=x; return 1;
}
}
}
return 0;
}
int main()
{
scanf("%d%d%lf%d%d",&n,&m,&t1,&t2,&v); t1/=60;
for(int i=1; i<=m; i++) scanf("%d%d",&a[i].x,&a[i].y);
for(int i=1; i<=n; i++)
{
scanf("%d%d",&b[i].x,&b[i].y);
for(int j=1; j<=m; j++)
{
tim[(i-1)*m+j]=(j-1)*(t1+t2)+t1;
for(int k=1; k<=m; k++) w[(i-1)*m+j].push_back(k);
}
}
double l=1,r=40000; n*=m;
while(l+e<r)
{
double ans=0;
mid=(l+r)/2;
memset(f,0,sizeof(f));
for(int i=1; i<=n; i++)
{
memset(visit,0,sizeof(visit));
if(match(i)) ans++;
}
if (ans==m) r=mid; else l=mid;
}
printf("%.6lf",l);
}