题目链接:
https://www.acwing.com/problem/content/376/
思路:
二分时间,得出每个炮塔最多发射多少炮弹,每个炮弹作为二分图右部,入侵者作为二分图左部。
每个炮弹各不相同,因为发射时间不同,能够在规定时间内击中即可连边。注意单位换算。
代码:
(感觉有瑕疵,对于极限值的估算没有把控好)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 struct Point 5 { 6 int x,y; 7 }; 8 int n,m; 9 double t1,t2,v; 10 Point a[60],b[60]; 11 12 const int N=5100; 13 const int M=250000; 14 int head[N],ver[2*M],nex[2*M],tot=1; 15 inline void add(int x,int y) 16 { 17 ver[++tot]=y; 18 nex[tot]=head[x]; 19 head[x]=tot; 20 } 21 22 inline double dist(double x1,double y1,double x2,double y2) 23 { 24 return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); 25 } 26 27 void build(double mi) 28 { 29 tot=1; 30 memset(head,0,sizeof(head)); 31 int ma=min((int)((mi+t2)/(t1+t2)),90); 32 for(int i=1; i<=m; ++i) 33 for(int j=1; j<=n; ++j) 34 { 35 double tt=dist(b[i].x,b[i].y,a[j].x,a[j].y)/v; 36 for(int k=1; k<=ma; ++k) 37 { 38 double t=t1*k+(k-1)*t2; 39 if(t+tt>mi)break; 40 add(i,j*100+k); 41 add(j*100+k,i); 42 } 43 } 44 } 45 46 bool vis[N]; 47 int match[N]; 48 bool dfs(int x) 49 { 50 for(int i=head[x],y; i; i=nex[i]) 51 if(!vis[y=ver[i]]) 52 { 53 vis[y]=1; 54 if(!match[y]||dfs(match[y])) 55 { 56 match[y]=x; 57 return true; 58 } 59 } 60 return false; 61 } 62 63 bool judge(double mi) 64 { 65 build(mi); 66 memset(match,0,sizeof(match)); 67 for(int i=1;i<=m;++i) 68 { 69 memset(vis,0,sizeof(vis)); 70 if(!dfs(i)) 71 return false; 72 } 73 return true; 74 } 75 76 double eps=1e-7; 77 double bi_search() 78 { 79 double l=0,r=(m+n-1)/n*(t1+t2)+40000/v; 80 while(r-l>eps) 81 { 82 double mi=(r+l)/2; 83 if(judge(mi)) 84 r=mi; 85 else l=mi; 86 } 87 return l; 88 } 89 90 int main() 91 { 92 scanf("%d%d%lf%lf%lf",&n,&m,&t1,&t2,&v); 93 v/=60; 94 t2*=60; 95 for(int i=1; i<=m; ++i) 96 scanf("%d%d",&b[i].x,&b[i].y); 97 for(int i=1; i<=n; ++i) 98 scanf("%d%d",&a[i].x,&a[i].y); 99 100 printf("%.6f",bi_search()/60); 101 return 0; 102 }