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 }