[博弈]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[博弈]相关的知识,希望对你有一定的参考价值。
http://blog.sina.com.cn/s/blog_83d1d5c70100y9yd.html
----很好的一篇sg函数资料,可惜不是sina用户转载不了.
hdu1846(记忆化搜索)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int cas,n,m; int sg[1010]; int dfs(int x) { if(x<=m)return sg[x]=1; if(sg[x]!=-1)return sg[x]; for(int i=1;i<=m;i++) if(dfs(x-i)==0)return sg[x]=1; return sg[x]=0; } int main() { scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); memset(sg,-1,sizeof(sg)); if(dfs(n)==1)printf("first\\n");else printf("second\\n"); //for(int i=1;i<=n;i++)printf("%d %d\\n",i,sg[i]); } }
hdu2188(和上题差不多)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int cas,n,m;int sg[10100]; int dfs(int x) { if(sg[x]!=-1)return sg[x]; if(x+m>=n)return sg[x]=1; for(int i=1;i<=m;i++) if(dfs(x+i)==0)return sg[x]=1; return sg[x]=0; } int main() { scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); memset(sg,-1,sizeof(sg)); if(dfs(0)==1)printf("Grass\\n");else printf("Rabbit\\n"); } }
取火柴问题 blog传送门:http://acm.hdu.edu.cn/forum/read.php?fid=9&tid=10617
定理实在太多了...blahblah...感觉自己最多只能沦为背背背选手..
预热题:
hdu1847(极短的代码)
每个人每次抓的牌只能是2的幂次.kiki先手
当只剩下三张牌时,先手必败.每一个数-1或-2都可以变成三的倍数,对于这一点要有足够的敏感度....想不到,回去面壁思过QAQ
所以当n为3的倍数时,kiki如果取走一点,cici都可以构造三的倍数,先手必败;
若n不为3的倍数,kiki可以把它构造成3的倍数,十分轻易.
#include<cstdio> #include<algorithm> using namespace std; int cas,n; int main() { while(scanf("%d",&n)!=EOF) { if(n%3==0)printf("Cici\\n");else printf("Kiki\\n"); } }
hdu1848 Fibonacci again and again
解题报告传送门:http://wenku.baidu.com/link?url=fVbzcnAnOOahfzy0Dk6YDuqYWFhRdsCrlfQ7J8E6G4ht_xAxggT9fMfFn6QJGnKag7aEhV_j7mzeB3v89cTsF_KXVTNi0mlIan6kzZHrA_q
先给出结论,这里要用到位运算,异或:^
游戏的某个位置(x1,x2,x3) x1,x2,x3表示3堆的个数。当且仅当 x1^x2^x3=0时,此点才是必败点P;
结论可以推广到一般情况,即有n堆,(x1,x2,x3,...xn) 当且仅当x1^x2^x3...^xn=0时,此点才是必败点P;
最后看下组合博弈,就是把简单的游戏组合起来,比如3堆的可以看成3个一堆的游戏。
定理:
假设游戏 Gi的SG函数是gi, i=1,…,n, 则
G = G1 + … + Gn 的 SG函数是
g(x1,…,xn) = g1(x1)⊕…⊕gn(xn).
其中那个符号就是异或^
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int f[1001]; int sg[1001];int b[1010]; int m,n,p; int main() { f[1]=1;f[2]=2; sg[0]=0;sg[1]=1;sg[2]=2;sg[3]=3; for(int i=3;f[i-1]<=1000;i++) f[i]=f[i-1]+f[i-2]; for(int i=4;i<=1000;i++) { sg[i]=i;memset(b,0,sizeof(b)); for(int j=0;f[j]<=i;j++) b[sg[i-f[j]]]=1;//遍寻i所能到达点集的sg值 for(int j=0;j<20;j++) { if(b[j]==0){sg[i]=j;break;} //找最小的未出现的sg值 } } while(scanf("%d%d%d",&m,&n,&p),(m!=0||n!=0||p!=0)) { if((sg[n]^sg[m]^sg[p])==0)printf("Nacci\\n"); else printf("Fibo\\n"); }return 0; }
吐槽:hdu的多组数据真是坑...........还有,原来^的优先级这么低!!!
2333感觉今天做了套杭电博弈专场.
以上是关于[博弈]的主要内容,如果未能解决你的问题,请参考以下文章