zoj3460(二分图,拆点,二分)
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, T1, T2 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 N, M, T1, T2 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, T1, T2, V 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; }