【题解】Alice ans Bob(博弈论)

题目大意:在黑板上又一个序列,每次操作可以选择一个数减1,或者是合并两个数,一个数被减至1则自动消除,不能操作者输。

解题思路:结论,对于大于1的数可以看成是一个整数s,为消除他们的总操作步数,包括减1以及合并,c为列中1的个数,如果s>2的话,c或者是s为奇数则为必胜,否则必败。若s≤2的话(s=2或者s=0)是,判断c是否为3的倍数,是的话必败,不是的话必胜。

证明:s>2时,s和c均为偶数是为必败态。

  1. s为奇数,c为偶数:先手操作,将s减1,转移至必败态。
  2. s为偶数,c为奇数:先手操作,将一个1减1,则c会减少1,转移至必败态。
  3. s为奇数,c为奇数:将一个1和s中的一个数合并。转移至必败态。
  4. s为偶数,c为偶数:s减1,则s为奇数c为偶数,必胜态;c减1,则s为偶数c为奇数,必胜态;合并1和非1数,s奇数c奇数,必胜态;

s=0者s=2时,当c%3=0时,为必败态。

  1. c%3=1时,将一个1减1,c%3==0,转移至必败态。
  2. c%3=2时,对于s=0,合并两个1,则变为s+2,c-2,此时如果s=0,则变为s=2时,c%3=0的必败态;对于s=2,将s减1,则变为s变为1,于是1的个数又增加1,所以c%3=0,必败态。
  3. c%3=0时,减掉一个1即为必胜态。
  4. 这里其实是个死循环,直至c=0
#include<cstdio> //如果s>2的话,c或者是s为奇数则为必胜,否则必败。 //若s≤2的话(s=2或者s=0)是,判断c是否为3的倍数,是的话必败,不是的话必胜。 //证明见我的博客 int n,cnt,sum,T,x; int liu() { if(sum>2) return (sum&1||cnt&1); return cnt%3; } int main() { scanf("%d",&T); for(int i=1;i<=T;i++) { sum=cnt=0; scanf("%d",&n); for(int j=1;j<=n;j++) { scanf("%d",&x); if(x==1) cnt++; else sum+=x; } if(cnt!=n) sum+=(n-cnt-1); printf("Case #%d: %s\n",i, liu() ? "Alice" : "Bob"); } }

模拟递归版:

dp[i][j]表示有i个石子数为1的堆数,其它堆合并再取完的步数为j。若值为1则先取者胜,为0为先取者输。
那么就有这几种情况:将某堆只能1的拿走;两堆是1的合并;把不是1的减一;把某堆是1的并到不是1的堆上

//cnt在收敛 #include<cstdio> #include<cstring> using namespace std; const int MAXN=1005; int n,cnt,sum,x,ans,dp[55][55*MAXN],T; int dfs(int cnt,int sum) { if(sum==1) cnt++,sum--;//否则不满足假设(必写) if(dp[cnt][sum]!=-1) return dp[cnt][sum]; int t=0; if(cnt==0) { dp[cnt][sum]=sum%2; return dp[cnt][sum]; } if(cnt>=1&&!dfs(cnt-1,sum)) t=1;//拿掉一个1 else if(sum>=1&&!dfs(cnt,sum-1)) t=1;//在非1堆进行一次操作(合并或减1) else if(cnt>=2&&sum>=1&&!dfs(cnt-2,sum+3)) t=1;//两个1合并成一堆,原先有堆 else if(cnt>=2&&sum==0&&!dfs(cnt-2,sum+2)) t=1;//两个1合并成一堆,原先没堆 else if(cnt>=1&&sum>=1&&!dfs(cnt-1,sum+1)) t=1;//一个1和非1堆合并 dp[cnt][sum]=t; return t; } int main() { memset(dp,-1,sizeof(dp)); scanf("%d",&T); for(int i=1;i<=T;i++) { sum=cnt=0; scanf("%d",&n); for(int j=1;j<=n;j++) { scanf("%d",&x); if(x==1) cnt++; else sum+=x; } if(cnt!=n) sum+=(n-cnt-1); ans=dfs(cnt,sum); printf("Case #%d: ",i); if(ans==1) printf("Alice\n"); else printf("Bob\n"); } return 0; }

————————————————
原文链接:收藏思维板块里


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530430.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(32)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示