http://acm.hdu.edu.cn/showproblem.php?pid=1525
题意:给你两个数,每次都是大数减去小数的整数倍,Stan先开始,然后是Ollie,如果谁先出现 0,b 这种情况谁就获胜了。
分析:1.当a=b时,这时候先手必胜。
2.当a>b时,这时候有两种情况
①a%b=0,此时a为b的倍数,先手必胜。
②a>=2b,此时先手可以进行选择,进行什么选择呢?每个人都想获胜,所以他们采取的都是最利于自己的行动,Stan或者Ollie肯定知道 a%b,b 是必胜态还是必败态。如果是必败态,先手将a,b变成a%b,b,使对手面临必败态,先手赢。如果是必胜态,先手将a,b变成 a%b+b,b ,破坏掉必胜态,那么对手只有将这两个数变成 a%b,b ,先手获胜。( 25,7 这个例子就能说明②这种情况 )
综上 关键是找到必胜态
a>b 与 b>a 情况一致
即a==b||a%b==0||a>=2*b时先手胜
否则就一步一步走,看到最后谁胜利。( 15,24这个例子能说明这种情况)
#include
#include
using namespace std;
int main()
{
long long a,b;
while(scanf("%lld%lld",&a,&b)!=EOF,a+b)
{
if(a=2*b)break;
a=a-b;
if(a
http://acm.hdu.edu.cn/showproblem.php?pid=1564
题意:一个nn的棋盘,一开始的时候棋子在一个角落的格子里,每次可以移动棋子到上下左右的相邻格子中(不能超过边界,而且不能走走过的格子);当不能走时,败。现在8600先走,问最后谁赢。
题解:这道题赢家的关键就是最先抢夺过程中剩余可以走的个数为奇数的状态,总的个数为nn刚开始可以走的个数为nn-1,如果n为偶数nn-1为奇数,则第一个走的人面临的就是必赢状态,否则第二走的人会赢。题解来源
#include
int main()
{
int n;
while(~scanf("%d",&n),n)
{
if(n&1) printf("ailyanlu\n");
else printf("8600\n");
}
return 0;
}
对称博弈
题目大意:给你n个硬币,把它围成一个圆圈。现在有两个人玩这样的一个翻转游戏,每次翻转1--k个硬币,最后一个翻转硬币者胜。
题解:1) 若k=1,则一次只能去翻一枚,奇数先手赢,偶数后手赢。
2)若k>1:
a: 先手一次翻完,先手赢;
b: 先手不能翻完,第一次必定断环。只要后手一次翻完,或将其分为相等数量的两段,
之后先手怎么操作后手就怎么操作,后手必赢。
#include
#include
using namespace std;
int main()
{
int t;
scanf("%d",&t);
for(int cas=1;cas<=t;cas++)
{
int n,k;
scanf("%d%d",&n,&k);
if(k==1)
{
if(n&1) printf("Case %d: first\n",cas);
else printf("Case %d: second\n",cas);
}
else {
if(k>=n) printf("Case %d: first\n",cas);
else printf("Case %d: second\n",cas);
}
}
return 0;
}
阶梯博弈
原作者的阶梯博弈详解
首先是对阶梯博弈的阐述...博弈在一列阶梯上进行...每个阶梯上放着自然数个点..两个人进行阶梯博弈...每一步则是将一个集体上的若干个点( >=1 )移到前面去..最后没有点可以移动的人输..
如这就是一个阶梯博弈的初始状态 2 1 3 2 4 ... 只能把后面的点往前面放...如何来分析这个问题呢...其实阶梯博弈经过转换可以变为Nim..把所有奇数阶梯看成N堆石子..做nim..把石子从奇数堆移动到偶数堆可以理解为拿走石子..就相当于几个奇数堆的石子在做Nim..( 如所给样例..234=5 不为零所以先手必败)为什么可以这样来转化?
假设我们是先手...所给的阶梯石子状态的奇数堆做Nim先手能必胜...我就按照能赢的步骤将奇数堆的石子移动到偶数堆...如果对手也是移动奇数堆..我们继续移动奇数堆..如果对手将偶数堆的石子移动到了奇数堆..那么我们紧接着将对手所移动的这么多石子从那个奇数堆移动到下面的偶数堆...两次操作后...相当于偶数堆的石子向下移动了几个..而奇数堆依然是原来的样子...即为必胜的状态...就算后手一直在移动偶数堆的石子到奇数堆..我们就一直跟着他将石子继续往下移..保持奇数堆不变...如此做下去..我可以跟着后手把偶数堆的石子移动到0..然后你就不能移动这些石子了...所以整个过程..将偶数堆移动到奇数堆不会影响奇数堆做Nim博弈的过程..整个过程可以抽象为奇数堆的Nim博弈...
其他的情况...先手必输的...类似推理...只要判断奇数堆做Nim博弈的情况即可...
为什么是只对奇数堆做Nim就可以...而不是偶数堆呢?...因为如果是对偶数堆做Nim...对手移动奇数堆的石子到偶数堆..我们跟着移动这些石子到下一个奇数堆...那么最后是对手把这些石子移动到了0..我们不能继续跟着移动...就只能去破坏原有的Nim而导致胜负关系的不确定...所以只要对奇数堆做Nim判断即可知道胜负情况...
https://vjudge.net/problem/POJ-1704
http://blog.sina.com.cn/s/blog_6a6aa7830100p4nb.html
题意:给定n个不同的数表示n个位置上有棋子,两个人轮流进行操作,不能操作的人输,每次可以选一个棋子然后向左移动至少一步并且不能越过别的棋子并且一个格子最多只能有一个棋子。判断先手能否必胜。
题解:由于只能向左移,而且不能相互交叉。我们把两个硬币之间的空间看作石子堆,一次左移相当于把某个石子堆(楼梯j)的石子移到了右边那个石子堆(楼梯j-1),最后的区间相当于最低的一层,题目实质就变成了阶梯博弈。
#include
#include
using namespace std;
int arr[1010];
int main()
{
int t,n,k,res;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
arr[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",arr+i);
}
sort(arr+1,arr+n+1);
if(n&1) k=1;
else k=2;
res=0;
for(;k<=n;k+=2)
{
res^=(arr[k]-arr[k-1]-1);
}
if(res) printf("Georgia will win\n");
else printf("Bob will win\n");
}
}
http://acm.hdu.edu.cn/showproblem.php?pid=4315
题意:有一群人在爬山,每个人有个离山顶的距离,且没有两个人在同一位置,可以多个人在山顶,其中有一个国王在位置k(标号),两个人轮流操作:任意选一个人然后将他向上移动至少位置1且不能越过其他人,谁将国王移动到山顶谁获胜。
题解:首先考虑没有king的情况,也就是说没有合法操作的那个人判负。这样的话,可以发现和上一道题的阶梯博弈是等效的。只需要将区间的距离看成是一堆一堆的石子,然后将编号为奇数的堆异或起来就行了。 但是有一个比较特殊的地方,就是king需要特判一下。当一共有奇数个人并且king在第二个人时,需要将第一个区间的长度-1,因为如果将第一个区间直接移动到山顶的话其实是一个必胜态,只有将第一个区间留下才是必败态。并且如果king在第一个人的话Alice必胜。
#include
#include
using namespace std;
int arr[1010];
int main()
{
int n,res,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",arr+i);
}
if(k==1) {
printf("Alice\n");
continue;
}
res=0;
if(k==2&&n&1) arr[0]=0;
else arr[0]=-1;
for(int i=n;i>=1;i-=2)
{
res^=(arr[i]-arr[i-1]-1);
}
if(res) printf("Alice\n");
else printf("Bob\n");
}
}