UVA - 11853-Paintball 求出口入口方法正確性分析

題目鏈接

題意

如果大家是從lrj的書中例題看到本題,相信對題意不會太陌生,所以就不重複說了

解題思路

書中lrj也講了思路,代碼也可以下載,這篇博客就是說明一下爲什麼入口和出口的求法的正確性。

樣例中敵人分佈

從圖片中可以看到樣例有解。建議大家先閱讀了代碼中求法及在什麼條件下調用該函數。看了後發現是在dfs中調
檢查該圓是否與左邊相交,如果相交說明從該圓與左邊的下交點到(0,1000)都不能作爲入口;如下圖所示

沒有延伸的情況

圖中與該條路徑已經沒有延伸,調用check_circle(),求得點left既爲入口最靠北的點;ps:我對與題目中所說的嚴格
大於敵人攻擊範圍的條件,但所求的確是等於的情況有點疑惑。

有延伸的情況

如上圖是有延伸的情況,但是依然滿足上面所說的最小交點(y值最小)便是滿足題意的入口。求出口的原理與入口相同。

代碼


// UVa11853 Paintball
// Rujia Liu

#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])));
}

// 能達到底部則返回true
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;    // 從上往下dfs
                break;
            }
        if(ok) printf("0.00 %.2lf %.2lf %.2lf\n", left, W, right);
        else printf("IMPOSSIBLE\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章