组合游戏(Circles Game,HDU 5299)
来源:互联网 发布:西瓜影音mac版 官方 编辑:程序博客网 时间:2024/06/05 14:39
很容易想到这是一个组合游戏。每个子游戏都是一棵有根树上的游戏,最后的答案就是每个子游戏SG值的Nim和。
有根树上的游戏就是给你一颗有根树,每次操作可以随便选取一个节点,并把这个节点所在的子树都删掉,不能操作者输。
那怎么计算每棵树的SG值呢?一开始尝试用经典的递推法去求,但是发现树的结构种类太多,不可能穷举,每种结构的后续状态也非常多,也不可能用每个后续节点来转移,而且记录树的信息很多,没有办法用简单的方法描述一棵树以及这个树的后续状态。所以把目标转向树形DP。希望只通过在子树上保存一些信息,然后根据这些信息快速地算出当前节点的SG值,同时维护信息。我一直考虑在子树上保存SG值以及mex()之类的信息,但是依然找不到一个简单靠谱的转移方法,既i避免不了穷举,更没有办法计算答案。最后没办法,只好手动计算各种不同结构的树的SG值,慢慢地找到了一些规律,就是如果两颗子树完全相同,那就可以同时删去,因为如果这是必败态,那么对手只需要模仿你的操作,你依然是必败态。如果这是必胜态,那么必然要让对方先动这两颗子树,你来模仿即可。后来想通了SG值可以完整地描述一个状态在组合游戏下的特征。换句话说,不仅仅是两颗完全相同的子树可以完全删去,其实只要他们的SG值相同,就可以当做是完全相同的子树,也就可以同时删去。后来又想通了SG值的意义,如果三个SG值异或起来等于0,那么这个游戏其实相当于两个SG值异或起来等于0的游戏。两个子游戏我们是通过模仿对方来取胜,三个子游戏其实也一样,只不过模仿的过程没有那么显然。
一边手算,一边思考,尝试寻找当前节点SG值与子节点SG值的关系。慢慢发现了我手算的所有数据都满足一个规律,那就是SG(u)=(SG(v)的异或和)+1。感觉自己应该是对的,但是不明白为什么,所以就从结论出发,尝试证明,最后想通了。
假如不允许取根节点,那么当前树的SG值就等于所有子树的SG值异或起来。现在允许取根节点,那么所有的状态都多了一个后续状态----空集,所以所有的SG值都+1,当前节点的SG值也不例外。
通过本题,我对SG值有了更深入的理解。同时也更加明白了就算你不知道一些冷门的定理,你依然可以通过思考和找规律猜出来甚至证明出来的道理。感觉很多时候你都需要这样去摸索的。
其实个定理不算冷门,只是自己知道的太少了。但是能够自己找到规律是应该的。
关于树上删边游戏的一些资料:
别人的题解:http://www.cnblogs.com/huoxiayu/p/4710749.html
百度文库资料:https://wenku.baidu.com/view/379e8baaa58da0116d174924.html
本题在建树时需要一些优化,不能O(n^2)暴力连边。
本题时间卡得很紧,可能需要把细节尽量优化好。
理论上来讲最坏还是O(n^2)的,但是就是给优化过了。
可能也就多校训练赛才会出那么经典的题目+这样卡优化吧。
代码:
#include<bits/stdc++.h>using namespace std;const int maxn = 20010;typedef long long ll;struct Point{ int x,y; Point(){}; Point(int x,int y):x(x),y(y){} void Read() { scanf("%d %d",&x,&y); }};struct Circle{ Point p; int r; Circle(){}; Circle(Point p,int r):p(p),r(r){} void Read() { p.Read(); scanf("%d",&r); } bool operator < (const Circle& rhs) const { return r<rhs.r; }};ll Dist2(Point A,Point B){ int x = A.x-B.x; int y = A.y-B.y; return 1ll*x*x+1ll*y*y;}bool In(Circle A,Circle B){ int d = B.r-A.r; return A.r<B.r&&1ll*d*d>Dist2(A.p,B.p);}int n;Circle c[maxn];vector<int>G[maxn];int p[maxn];int dfs(int u){ int ret=0; for(int i=0;i<(int)G[u].size();i++) ret^=dfs(G[u][i]); return ret+1;}void solve(){ scanf("%d",&n); for(int i=1;i<=n;i++) { c[i].Read(); G[i].clear(); p[i]=0; } sort(c+1,c+1+n); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(In(c[i],c[j])) { p[i]=j; break; } for(int i=1;i<=n;i++) if(p[i]) G[p[i]].push_back(i); int nim = 0; for(int i=1;i<=n;i++) if(!p[i]) nim^=dfs(i); if(nim) puts("Alice"); else puts("Bob");}int main(){ int T; scanf("%d",&T); while(T--) solve(); return 0;}
- 组合游戏(Circles Game,HDU 5299)
- HDU 5299 Circles Game
- HDU 5299 Circles Game
- hdu 5299 Circles Game
- HDU 5299 Circles Game
- hdu 5299 Circles Game
- hdu 5299 Circles Game(博弈)
- hdu 5299(树上删边游戏) Circles Game
- HDU 5299 Circles Game(树的删边游戏)
- HDU 5299 Circles Game(树&博弈)
- hdu 5299——Circles Game
- hdu 2147 kiki‘game(组合游戏-博弈)
- hdu 1079 Calendar Game 博弈(组合游戏) sg函数
- [多校2015.01.1012 博弈] hdu 5299 Circles Game
- hdu 5299 Circles Game 2015 Multi-University Training Contest 1
- HDU 5299 Circles Game (圆的扫描线+树上SG)
- 【Game】组合游戏入门
- hdu 题目2147 kiki's game (组合游戏,必败点和必胜点)
- Swing学习----------java的布局管理学习总结(一)
- 蓝桥杯比赛总结
- Activity标题栏添加返回按钮
- gulp的安装&less插件
- 编写java程序151条建议读书笔记(8)
- 组合游戏(Circles Game,HDU 5299)
- 数据结构之队列
- 在tomcat上发布servlet访问mysql数据库完成登录功能的案例经验总结
- Maven pom.xml配置详解
- iOS蓝牙开发
- python基础操作
- 磁盘I/O中几种访问文件的方式
- Linux基本操作命令(二)
- 蓝桥杯第1,5,7题