题目链接:
https://ac.nowcoder.com/acm/contest/11166/A
题目大意
有两堆石头,数量分别为 n,m 。两个人轮流操作,每次可以从一堆石头中拿走 k(k>0) 块石头,在另一堆中拿走 s*k(s≥0) 个石头。
不能操作者输。双方均采取最优策略,求先手胜还是后手胜。
题解
因为Alice和Bob的每一步操作都是最优解,所以若当前操作者处于一个必胜的状态时,则操作后的状态一定为必输状态,所以只需根据必输状态推出必胜状态,再将推出的状态记录即可。
假设当前必输状态为 (x,y)(x,y)(x,y)
则可推出的必胜状态为 [x+i,y+i∗j][x+i,y+i*j][x+i,y+i∗j] 与 [x+i∗j,y+i][x+i*j,y+i][x+i∗j,y+i] (i为大于0的整数,j为大于等于0的整数)
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N=5050;
int dp[N][N];
int main()
{
dp[0][0]=0;//0为Alice必输的状态
for(int x=0;x<N;x++)
for(int y=0;y<=x;y++)
{
if(dp[x][y]==0)
{
for(int i=1;i+x<N;i++)
for(int j=0;i*j+y<N;j++)
{
int xx=i+x,yy=i*j+y;
if(xx<yy)swap(xx,yy);
dp[xx][yy]=1;
}
for(int i=1;i+y<N;i++)
for(int j=0;i*j+x<N;j++)
{
int xx=i*j+x,yy=i+y;
if(xx<yy)swap(xx,yy);
dp[xx][yy]=1;
}
}
}
int T,n,m;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
if(n<m)swap(n,m);
if(dp[n][m])printf("Alice\n");
else printf("Bob\n");
}
return 0;
}
这是一个关于博弈论的问题,双方轮流从两堆石头中拿取,每次操作要遵循一定的规则。若采取最优策略,如何判断先手或后手会获胜?该文解析了问题的思路并提供了参考代码。
1678

被折叠的 条评论
为什么被折叠?



