HDU 5299 Circles Game(樹&博弈)
阿新 • • 發佈:2019-02-12
本文純屬原創,轉載註明出處,謝謝。
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Alice and Bob are playing a game concerning these circles.They take turn to play,Alice goes first:
1、Pick out a certain circle A,then delete A and every circle that is inside of A.
2、Failling to find a deletable circle within one round will lost the game.
Now,Alice and Bob are both smart guys,who will win the game,output the winner's name.
Input The first line include a positive integer T<=20,indicating the total group number of the statistic.
As for the following T groups of statistic,the first line of every group must include a positive integer n to define the number of the circles.
And the following lines,each line consists of 3 integers x,y and r,stating the coordinate of the circle center and radius of the circle respectively.
n≤20000,|x|≤20000,|y|≤20000,r≤20000。
Output If Alice won,output “Alice”,else output “Bob”
Sample Input 2 1 0 0 1 6 -100 0 90 -50 0 1 -20 0 1 100 0 90 47 0 1 23 0 1
Sample Output Alice Bob
2015多校1的一道非常棒的題。
題意是有n個圓,相互之間的關係要麼是包含,要麼是相離。現在每次可以選擇一個圓取走,取掉這個圓的時候,被它包含的所有圓都會被一併取走。現在Alice和Bob輪流以最佳策略取圓,誰取完誰贏。
那麼拿到這個題,首先第一反應就是博弈。然後去博弈的模型裡面找,發現“奇異局勢”的“取石子游戲”模型跟這個似乎非常相似。確實,如果這個題所有包含的圓都是一個套一個的話,就跟取石子游戲的模型一模一樣了。可以直接把所有堆的數字異或起來就行。
但是這個題不同的地方在於可能一個圓包含著兩個相離的圓,而這樣就與之前的模型有一定的區別了。
這個時候我們可以想象一下,最初的跟取石子游戲相同的那個圓的模型,其實可以相當於最最外層有一個非常非常大的圓把他們套在一起,那麼這樣就能聯想到把同層相離的若干個圓先做一次異或,就能將其轉化為一個圓套圓的模型了,這麼逐步向外計算下去,就能得到最後的結果了。
而到了這裡,就是這個題最後的一個難點了:建樹。
這些圓一個套一個的模型,就像是樹。被包含的圓是包含它的圓的子節點,而同一層相離的圓則互為兄弟節點,進行上面的運算的時候,就將這個節點所有子節點先異或起來就好。
下面貼程式碼。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <queue> #include <map> #include <stack> #include <set> #include <cmath> #include <vector> #define INF 0x3f #define eps 1e-6 using namespace std; struct ss { long long x; long long y; long long r; }a[20000+100]; bool cmp(ss x,ss y) { return x.r>y.r; } int judge(int x,int y)//判斷兩圓位置關係,內含返回1,相離返回0 { if((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y)<(a[x].r+a[y].r)*(a[x].r+a[y].r)) return 1; return 0; } vector<int> b[20000+100];//b[i]存第i個圓的子節點 void fi(int y,int x)//找到當前圓應該存在的地方 { for(int i=0;i<b[x].size();i++) { if(a[y].r==a[b[x][i]].r) break; if(fuck(y,b[x][i])==1) { fi(y,b[x][i]); return; } } b[x].push_back(y); } int play(int x)//執行異或操作 { int ans=0; for(int i=0;i<b[x].size();i++) ans^=play(b[x][i]); return ans+1; } int main() { int T; cin>>T; while(T--) { int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y>>a[i].r; for(int i=0;i<=n;i++) b[i].clear(); sort(a+1,a+n+1,cmp);//排序,按半徑從大到小,保證後面的圓一定不會包含前面的圓 for(int i=1;i<=n;i++) fi(i,0); int ans=play(0); ans-=1; if(ans!=0) cout<<"Alice"<<endl; else cout<<"Bob"<<endl; } return 0; }