題目鏈接
題意
如果大家是從lrj的書中例題看到本題,相信對題意不會太陌生,所以就不重複說了
解題思路
書中lrj也講了思路,代碼也可以下載,這篇博客就是說明一下爲什麼入口和出口的求法的正確性。
從圖片中可以看到樣例有解。建議大家先閱讀了代碼中求法及在什麼條件下調用該函數。看了後發現是在dfs中調
檢查該圓是否與左邊相交,如果相交說明從該圓與左邊的下交點到(0,1000)都不能作爲入口;如下圖所示
圖中與該條路徑已經沒有延伸,調用check_circle(),求得點left既爲入口最靠北的點;ps:我對與題目中所說的嚴格
大於敵人攻擊範圍的條件,但所求的確是等於的情況有點疑惑。
如上圖是有延伸的情況,但是依然滿足上面所說的最小交點(y值最小)便是滿足題意的入口。求出口的原理與入口相同。
代碼
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000 + 5;
const double W = 1000.0;
int n, vis[maxn];
double x[maxn], y[maxn], r[maxn], left, right;
bool ok;
bool intersect(int c1, int c2)
{
return sqrt((x[c1]-x[c2])*(x[c1]-x[c2]) + (y[c1]-y[c2])*(y[c1]-y[c2])) < r[c1] + r[c2];
}
void check_circle(int u)
{
if(x[u] - r[u] < 0)
left = min(left, y[u] - sqrt(r[u]*r[u] - x[u]*x[u]));
if(x[u] + r[u] > W)
right = min(right, y[u] - sqrt(r[u]*r[u] - (W-x[u])*(W-x[u])));
}
bool dfs(int u)
{
if(vis[u]) return false;
vis[u] = 1;
if(y[u] - r[u] < 0) return true;
for(int v = 0; v < n; v++)
if(intersect(u, v) && dfs(v)) return true;
check_circle(u);
return false;
}
int main()
{
while(scanf("%d", &n) == 1)
{
ok = true;
left = right = W;
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++)
scanf("%lf%lf%lf", &x[i], &y[i], &r[i]);
for(int i = 0; i < n; i++)
if(y[i] + r[i] >= W && dfs(i))
{
ok = false;
break;
}
if(ok) printf("0.00 %.2lf %.2lf %.2lf\n", left, W, right);
else printf("IMPOSSIBLE\n");
}
return 0;
}