UVA 11853 Paintball(几何数学+DFS)

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 }
原文地址:https://www.cnblogs.com/YingZhixin/p/7518145.html