cychester

BZOJ 3007 [SDOI2012]拯救小云公主 - 对偶图 + 并查集

Solution

答案具有单调性, 显然可以二分答案。

有两个注意点 : 英雄是可以随便走的, 也就是不是网格图。。。 还有坐标不能小于$1$ QAQ

 

开始时英雄在左下角, 公主在右上角, 我们反过来考虑, 让英雄不能到达公主那。

把每个boss 看作是以其坐标为圆心, $mid$为半径的圆。

这时必须满足条件  : 矩形的下边和 左边或上边能通过圆连接

        或者 矩形的 右边 和  左边或上边能通过圆连接。

这样我们只需把 下边和右边看作一个点, 左边和上边看作一个点 , 用并查集合并能够通过圆连接的boss 和 边界。

最后判断两个边界是否在同一集合内即可。

 

Code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #define R register
 5 #define rd read()
 6 using namespace std;
 7 
 8 const int N = 3e3 + 100;
 9 const double eps = 1e-4;
10 const double EPS = 1e-6;
11 
12 int n, row, line;
13 int S, T;
14 int f[N];
15 double Dis[N][N];
16 
17 struct node {
18     int x, y;
19 }pos[N];
20 
21 inline int read() {
22     int X = 0, p = 1; char c = getchar();
23     for(;c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
24     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
25     return X * p;
26 }
27 
28 int get(int x) {
29     return f[x] == x ? x : f[x] = get(f[x]);
30 }
31 
32 inline void merge(int x, int y) {
33     x = get(x); y = get(y);
34     f[x] = y;
35 }
36 
37 inline double cal(int i, int j) {
38     double x = pos[i].x - pos[j].x;
39     double y = pos[i].y - pos[j].y;
40     return sqrt(x * x + y * y);
41 }
42 
43 bool jud(double dis) {
44     for(R int i = 0; i <= n + 1; ++i)
45         f[i] = i;
46     for(R int i = 1; i <= n; ++i) 
47         if(pos[i].x + dis + EPS >= row || pos[i].y - dis - EPS <= 1)
48             merge(0, i);
49     for(R int i = 1; i <= n; ++i)
50         if(pos[i].x - dis - EPS <= 1 || pos[i].y + dis + EPS >= line)
51             merge(i, n + 1);
52     for(R int i = 1; i <= n; ++i)
53         for(R int j = i + 1; j <= n; ++j) {
54             int x = get(i), y = get(j);
55             if(x == y) continue;
56             if(Dis[i][j] <= 2 * dis)
57                 merge(i, j);
58         }
59     return get(0) != get(n + 1);
60 }
61 
62 int main()
63 {
64     n = rd; row = rd; line = rd;
65     S = 0, T = n + 1;
66     for(R int i = 1; i <= n; ++i)    pos[i].x = rd, pos[i].y = rd;
67     for(R int i = 1; i <= n; ++i)
68         for(R int j = i + 1; j <= n; ++j)
69             Dis[i][j] = cal(i, j);
70     double l = 0, r = row;
71     int cnt = 60;
72     if(line > row) r = line;
73     while(l + eps < r && cnt--) {
74         R double mid = (l + r) / 2;
75         if(jud(mid)) l = mid;
76         else r = mid;
77     }
78     printf("%.2lf\n", l);
79 }
View Code

 

posted on 2018-09-16 07:21  cychester  阅读(202)  评论(0编辑  收藏  举报

导航