【JZOJ B组】【NOIP2013模拟】导弹防御塔

16 篇文章 0 订阅
2 篇文章 0 订阅

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值