zoj3460(二分图,拆点,二分)

202 篇文章 0 订阅
123 篇文章 0 订阅

Description

You control N missile launching towers. Every tower has enough missiles, but for each tower only one missile can be launch at the same time. Before the launching, every missile need T1 seconds to leave the tower. Assume that all the missiles have the same speed V, and it would fly along the shortest path to the target. You can just consider the horizontal distance and ignore the height. You can consider the time equal to distance / V (minutes). The missile can immediately destroy the target when it reached. Besides, for the same tower, after launching a missile, it need T2 minutes to prepare for the next one.

Now, give you the coordinate position of N missile launching towers and M targets, T1T2 and V, you should find the minimum minutes to destroy all the targets.

Input

The input will consist of about 10 cases. The first line of each case contains five positive integer numbers NMT1T2 and V, decribed as above. The next M lines contains two integer numbers indicating the coordinate of M targets. The continueing N lines contains two integer numbers indicating the coordinate of N towers.
To all the cases, 1 ≤ N ≤ 50, 1 ≤ M ≤ 50
The absolute value of all the coordinates will not exceed 10000, T1T2V will not exceed 2000.

Output

For each case, the output is only one line containing only one real number with six digits precision (after a decimal point) indicating the minimum minutes to destroy all the targets.

Sample Input

3 3 30 20 1
0 0
0 50
50 0
50 50
0 1000
1000 0

Sample Output

91.500000


题意:用N个导弹发射塔攻击M个目标。每个导弹发射塔只能同时为一颗导弹服务,发射一颗导弹后需要T1(这里用的是秒)的时间才能离开当前的导弹发射塔,一颗导弹从发射到击中目标的时间与目标到发射塔的距离有关(直线距离),每颗导弹发射完成之后发射塔需要T2的时间准备下一个。现在给出N个导弹发射塔和M个目标的位置坐标以及T1,T2,V,问用这N个导弹发射塔最少需要多少时间可以击毁所有M个目标。

思路:由于发射的时候要准备时间t2以及发射时间t1,我们无法用N个导弹直接去和M个目标匹配,因为导弹打了一个还能继续打另一个,可是打另一个的时间又无法用建N匹配M的图去表现出来。所以,脑洞大开的我们想到把N个炮台拆点,每个炮台第i次打到第j个点,其中i<=M,j<=M,所以这样就能建一个N*M匹配M的图出来,由于数据允许,所以可以这么建。然后建完图确实可以进行匹配,可是题目要求最少的时间,我们匹配只能确定最多的点被打中。。。。。。所以在这里假设最少时间我们已经知道了,进行二分,将时间少于mid的边不加,如果是完美匹配,就缩小r范围,如果不能完美匹配,就扩大l范围呗= =!


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
typedef long long ll;
double dd[3000][50];
const int N=3000;///两边的最大数量
int from[N];///记录右边的点如果配对好了它来自哪里
bool use[N];///记录右边的点是否已经完成了配对
vector <int>tu[N];
int n;///m,n分别表示两边的各自数量,n是左边,m是右边
bool dfs(int x)
{
    int l=tu[x].size();
    for(int i=0; i<l; i++) ///m是右边,所以这里上界是m
        if(!use[tu[x][i]])
        {
            use[tu[x][i]]=1;
            if(from[tu[x][i]]==-1||dfs(from[tu[x][i]]))
            {
                from[tu[x][i]]=x;
                return 1;
            }
        }
    return 0;
}
int hungary()
{
    int tot=0;
    memset(from,-1,sizeof(from));
    for(int i=1; i<=n; i++) ///n是左边,所以这里上界是n
    {
        memset(use,0,sizeof(use));
        if(dfs(i))
            tot++;
    }
    return tot;
}
struct zb
{
    double x,y;
} a[55],b[55];
double t1,t2,v;
double dis(int i,int j)
{
    return sqrt((a[i].x-b[j].x)*(a[i].x-b[j].x)+(a[i].y-b[j].y)*(a[i].y-b[j].y));
}
int main()
{
    int N,M;
    while(~scanf("%d%d%lf%lf%lf",&N,&M,&t1,&t2,&v))
    {
        t1/=60.0;
        for(int i=1; i<=M; i++)scanf("%lf%lf",&a[i].x,&a[i].y);
        for(int i=1; i<=N; i++)scanf("%lf%lf",&b[i].x,&b[i].y);
        for(int i=1; i<=N; i++)
            for(int j=1; j<=M; j++)
                for(int k=1; k<=M; k++)
                    dd[(i-1)*M+j][k]=t1*j+dis(k,i)/v+t2*(j-1);
        n=M;
        double l=0,r=2000000000000,mid;
        while(r-l>1e-8)
        {
            for(int i=1; i<=M; i++)
                tu[i].clear();
            mid=(l+r)/2.0;
            for(int i=1; i<=M*N; i++)
                for(int j=1; j<=M; j++)
                    if(dd[i][j]<=mid)
                        tu[j].push_back(i);
            if(hungary()==M)
                r=mid;
            else l=mid;
        }
        printf("%.6f\n",r);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值