10.23T2 二分+二分图(滑稽)

#3847 轰炸

描述

Ljr 家里有矿。

Ljr 有 M 套房子,你可以把它们分别看成 M 个点分布在直角坐标系中,Jerryzhong 非常 痛恨 ljr 这个青春富豪,于是他想要炸掉 ljr 的这 M 套房子。

Jerryzhong 通过红石科技造了 N 台红石大炮,由于客户端不兼容,因此这 N 台大炮随 机分布在了这个直角坐标系中,每一台红石大炮的炮弹需要 t1 分钟发射,发射一枚炮弹之 后需要 t2 分钟重新装弹,炮弹飞行的速度为 v/分钟,他想知道最少需要多少时间才能轰炸 完 ljr 的 M 套房子,由于 Jerryzhong 忙着做(shui)题(tie),因此他将这件事情拜托给了你,你 能回答这个问题吗?

你可以认为 N 台大炮一开始都已经填装好了弹药,且炮台和房子的距离为欧几里得距 离,所有炮弹无视地形限制,水平飞行,Jerryzhong 可以同时使用多个炮台,但每个炮台一 次只能发射一枚炮弹,炸掉房子不需要时间。

由于 ljr 是个阔佬,所以他能够重新买 Q-1 次房,因此 Jerryzhong 会向你询问 Q 次炸完 房子的最少时间。

输入

第一行一个数 Q 表示询问次数。

接下来一行 5 个整数 N,M,t1,t2,v 意义如题所述。

接下来 N 行,每行两个数 x,y,表示 N 台红石炮的坐标。

接下来 M 行,每行两个整数 x,y,表示 ljr 的 M 套房子的坐标。

输出

共 Q 行,每行一个实数表示最少时间,精确到小数点后 6 位。

样例输入[复制]
1
3 3 30 20 1
50 50
0 1000
1000 0
0 0
0 50
50 0
样例输出[复制]
180.000000
提示

numQ N M 其他

1 =1 ≤3 ≤2 无

2 =1 ≤6 ≤5 无

3 =1 ≤10 ≤10 v=1

4 =1 ≤10 ≤10 t2=0

5 =1 ≤10 ≤10 t1=0

6 ≤5 ≤50 ≤50 t1=0,t2=0

7 ≤5 ≤50 ≤50 v=1

8 ≤10 ≤50 ≤50 无

9 ≤15 ≤50 ≤50 无

10 ≤15 ≤50 ≤50 无

标签
ZYH
 
 
 
 
 
拆出m个点代表第i次攻击,然后二分时间,如果小于mid的两点连起来,看是否构成m组匹配就可以了
当然这里我加了一点优化,直接实数二分是要炸掉的
我们可以知道这个答案肯定是某一个炮弹打中的时间点,所以我们可以把所有的时间点给求出来然后排序,在上面二分就很方便了
code:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iomanip>
 6 #include<algorithm>
 7 #define N 105
 8 using namespace std;
 9 long long n,m;
10 double v,t2,t1;
11 double eps=1e-9;
12 long long matching[N],vis[N],g[10005][100],paox[N],paoy[N],fangx[N],fangy[N];
13 double dis[20000][100],Tim[125005];
14 int tot;
15 bool match(long long u) {
16     for(long long i=1; i<=m; i++) {
17         if(vis[i]||!g[u][i])continue;
18         vis[i]=1;
19         if(!matching[i]||match(matching[i])) {
20             matching[i]=u;
21             return true;
22         }
23     }
24     return false;
25 }
26 long long hun() {
27     long long ans=0;
28     for(long long i=1; i<=n*m; i++) {
29         memset(vis,0,sizeof vis);
30         if(match(i))ans++;
31     }
32     return ans;
33 }
34 double sq(double x) {
35     return x*x;
36 }
37 double getdis(long long i,long long j) {
38     return sqrt(sq(paox[i]-fangx[j])+sq(paoy[i]-fangy[j]));
39 }
40 bool check(double mid) {
41     memset(g,0,sizeof g);
42     for(long long i=1; i<=m; i++) { //拆点
43         for(long long j=1; j<=n; j++) { //
44             for(long long k=1; k<=m; k++) {
45                 if(dis[(j-1)*m+i][k]-eps<=mid) {
46                     g[(j-1)*m+i][k]=1;
47                 }
48             }
49         }
50     }
51     if(hun()==m)return true;
52     return false;
53 }
54 int main() {
55     long long Q;
56     cin>>Q;
57     while(Q--) {
58         tot=0;
59         cin>>n>>m>>t1>>t2>>v;
60         for(long long i=1; i<=n; i++)cin>>paox[i]>>paoy[i];
61         for(long long i=1; i<=m; i++)cin>>fangx[i]>>fangy[i];
62         
63         double ans;
64         for(long long i=1; i<=m; i++) { //拆点
65             for(long long j=1; j<=n; j++) { //
66                 for(long long k=1; k<=m; k++) {
67                     dis[(j-1)*m+i][k]=getdis(j,k)/v+(t2+t1)*i-t2;
68                     Tim[++tot]=dis[(j-1)*m+i][k];
69                 }
70             }
71         }
72         sort(Tim+1,Tim+1+tot);int l=1,r=tot;
73 //        for(int i=1;i<=tot;i++)cout<<Tim[i]<<" ";cout<<"
";
74 //        cout<<check(Tim[6])<<" sss
";
75 //        for(int i=1;i<=tot;i++){
76 //            memset(matching,0,sizeof matching);
77 //            cout<<"i="<<i<<" Check="<<check(Tim[i])<<"
";
78 //        }
79         while(l<=r) {
80             memset(matching,0,sizeof matching);
81             int mid=(l+r)/2;
82             if(check(Tim[mid]))r=mid-1,ans=Tim[mid];
83             else l=mid+1;
84         }
85         cout<<fixed<<setprecision(6)<<ans<<'
';
86     }
87     return 0;
88 }

over

原文地址:https://www.cnblogs.com/saionjisekai/p/9838298.html