Question:題目詳情(http://vjudge.net/contest/134361#problem/C)
題目大意:有一個1000*1000的方陣(建立座標),這之間有一些士兵有具體的座標,並且具有一定的攻擊半徑,現你要從最左邊進入,途中避開所有的士兵(不被攻擊),從最右邊出,如果有多解則輸出離北邊最近的額座標
解題思路:可以把士兵看成一個個圓,看成池塘的石頭,如果能從池塘的最北邊走石頭走到最南邊則不可能避開所有的士兵,因爲左右兩邊不連通。如果不能從北邊走到南邊,從北邊出發找到與左邊相交的圓,取相連的圓與左邊邊界相交的最小值即爲起點,右邊雷同左邊,詳情見代碼
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000+5;
struct node
{
int x,y,r;
}a[maxn];
int vis[maxn],n;
double ans1,ans2;
bool judge(node b,node c) //判斷兩個人是否相交
{
return (b.x-c.x)*(b.x-c.x)+(b.y-c.y)*(b.y-c.y)<=(b.r+c.r)*(b.r+c.r);
}
bool dfs(int u)
{
vis[u]=1;
if(a[u].y-a[u].r<=0) return false; //如果既與北邊連通,又與南邊相交,則不可能成功
if(a[u].x-a[u].r<=0) ans1=min(ans1,a[u].y-sqrt(a[u].r*a[u].r-a[u].x*a[u].x)); //如果與左邊邊界相交,則取較小的一個交點
if(a[u].x+a[u].r>=1000) ans2=min(ans2,a[u].y-sqrt(a[u].r*a[u].r-(1000-a[u].x)*(1000-a[u].x))); //如果與右邊邊界相連,則取交點最小的一個
for(int i=0;i<n;i++)
{
if(!vis[i]) //節點沒有被訪問過
{
if(judge(a[u],a[i])) //如果兩個圓相交,則繼續
if(!dfs(i)) return false ; //如果相交的圓與最南邊相交則失敗
}
}
return true;
}
void solve()
{
for(int i;i<n;i++)
{
if(!vis[i]&&a[i].y+a[i].r>=1000) //前提是從北邊出發,與北邊有交點
if(!dfs(i)) {printf("IMPOSSIBLE\n");return ;}//如果左右不連通則說明不能成功
}
printf("0.00 %.2f 1000.00 %.2f\n",ans1,ans2);
}
int main()
{
while(~scanf("%d",&n))
{
ans1=1000;
ans2=1000;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].r);
solve();
}
return 0;
}
體會:開始沒想到,看了題解以後才豁然開朗,又是必須要轉化思路,簡化問題