https://vjudge.net/problem/UVA-11853
根据题意描述,相当于在一个正方形中有若干个圆形障碍物,问是否能从左边界走到右边界。判断是否有解需要一点创造性的思维:不妨把正方形当做一个湖,所有的圆形都是垫脚石,假设我们可以从上边界“踩着”垫脚石成功走到下边界,说明左右边界是不连通的;否则就是连通的。想到了这里,便不难用dfs或bfs来判断是否有解了:每次都从和上边界相交的圆开始进行dfs,如果遇到某个圆和下边界也相交,那么无解。
这样解的存在性只需要一次DFS或者BFS判连通即可。如何求出最北的进/出位置呢?方法如下:从上边界开始遍历,沿途检查与边界相交的圆。这些圆和左边界的交点中最靠南边的一个就是所求的最北进入位置,和右边界的最南交点就是所求的最北离开位置。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 #include<algorithm> 4 #include<string> 5 #include<sstream> 6 #include<set> 7 #include<vector> 8 #include<stack> 9 #include<map> 10 #include<queue> 11 #include<deque> 12 #include<cstdlib> 13 #include<cstdio> 14 #include<cstring> 15 #include<cmath> 16 #include<ctime> 17 #include<functional> 18 using namespace std; 19 20 #define N 1000+10 21 struct Circle 22 { 23 int x, y, r; 24 void read() 25 { 26 scanf("%d%d%d", &x, &y, &r); 27 } 28 }c[N]; 29 double ans1, ans2; 30 int n, vis[N]; 31 32 bool can(Circle a, Circle b)//判断两个圆是否相交或相切 33 { 34 int dx = a.x - b.x; 35 int dy = a.y - b.y; 36 return dx*dx + dy*dy - (a.r + b.r)*(a.r + b.r) <= 0; 37 } 38 bool dfs(int u) 39 { 40 vis[u] = 1; 41 if (c[u].y - c[u].r <= 0)return false;//圆和下边界有交点,说明不存在解,直接退出 42 if (c[u].x - c[u].r <= 0)ans1 = min(ans1, c[u].y - sqrt(c[u].r*c[u].r - c[u].x*c[u].x));//与左边界有交点,取纵坐标的较小者 43 if (1000 - c[u].x - c[u].r <= 0)ans2 = min(ans2, c[u].y - sqrt(c[u].r*c[u].r - (1000 - c[u].x)*(1000 - c[u].x)));//与右边界有交点,取纵坐标较小者 44 for (int i = 0; i < n; i++) 45 if (!vis[i]) 46 { 47 if (can(c[u], c[i]))//路径可以继续扩展 48 if (!dfs(i))return false; 49 } 50 return true; 51 } 52 void solve() 53 { 54 ans1 = ans2 = 1000; 55 for (int i = 0; i < n; i++) 56 if (!vis[i] && c[i].y + c[i].r>=1000)//从与上边界有交点的圆出发 57 { 58 if (!dfs(i))//不存在解,如果存在解那么每次dfs后都会更新解 59 { 60 puts("IMPOSSIBLE"); 61 return; 62 } 63 } 64 printf("0.00 %.2lf 1000.00 %.2lf ", ans1, ans2); 65 } 66 int main() 67 { 68 //freopen("t.txt", "r", stdin); 69 while (~scanf("%d", &n)) 70 { 71 memset(vis, 0, sizeof(vis)); 72 for (int i = 0; i < n; i++) 73 c[i].read();//利用成员函数方便读入数据 74 solve(); 75 } 76 return 0; 77 }