导弹防御塔——二分图多重匹配(拆点法)

题目链接:

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 }
View Code

 

转载于:https://www.cnblogs.com/judp/p/11253854.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值