POJ1740 A New Stone Game 博弈

来源:互联网 发布:unity3d怎么注册 编辑:程序博客网 时间:2024/05/17 07:31

题意:

给定n堆石子,比如n=3,pile=(4,5,7),表示第1,2,3堆分别有石子4,5,7个。

Alice和Bob进行取石子游戏。

总是A先move。

每次move:

1.必须选中某堆:

2.在该堆中移除至少1个石子。(必选操作)

3.将该堆中的石子任意个数移到任何其他非空石子堆里去。(可选操作)

最当AB都有最优策略进行游戏时,最后胜者是谁。


思路:

1.

n=1时显然A肯定赢。

2.

n=2时状态(x,y);x<=y.

比如(1,1) ,此时A肯定输。

比如(1,2),此时A肯定赢,因为当A可以将(1,2)转换为(1,1)。(1,1)轮到B,B则死路一条。

比如(2,2), A输。

比如(2,3),A赢。

到这就发现蹊跷了吧?推广之:

比如(x,x),此时A肯定要输。因为无论A如果操作,将(x,x)转化为(x,y);y<x;B都会将(x,y)转化为(y,y)。不断下去最后A还是泪流满面地面临(1,1)的死路。

那(x,y)呢,显然此时A肯定要赢。因为(x,y)马上可以转化为(y,y),由上句可知,B就死定了。

3.

n=3.

(x,y,z);x<=y<=z;

显然当x=0时,即用n=2,(y,z)的思路来判断即可。

所以n=3时候x!=0;

而由n=2的思路可知,如果A将(x,y,z)转化为(0,y,y)后,B就输了。所以A的最佳策略是(x,y,z)转化为(0,y,y)

实际上是可以实现的:

取出z的y-x个石头(显然z>=y>y-x)(x!=0),然后将其放到x堆上,然后将z剩下的石头扔掉。

所以当n=3时,A赢。

4.

n=4时(x,y,z,k),显然A的最佳策略是取完之后还是n=4,因为如果n=3则B稳赢。

先考虑(x,x,y,y),(1,1,1,1)稳输,(1,1,2,2)稳输,所以先猜测(x,x,y,y)稳输。

因为(x,x,y,y)经过操作后,不会再是(i,i,j,j),不信可以(1,1,4,4)去试看看就知道为什么了。

而无论A对(x,x,y,y)进行任何操作变成(w,x,y,z),B都可以对(w,x,y,z)进行对称操作再转化为(w,w,x,x)。举例(1,1,5,5)=>(2,1,4,5) (2,1,4,5)=>(2,2,4,4)

这样一直下去A的下场还是1,1,2,2,或者1,1,1,1。还是稳输。

所以(x,x,y,y),A稳输。

而对于一般的(w,x,y,z)肯定可以转化为(i,i,j,j),不信举例几个试试就懂了。

所以面临一般的(w,x,y,z)时A稳赢了。


ok,到这其实就差不多了。就题论题,要勇敢地猜测勇敢地提交,否则再推倒下去不是时间不够就是反胃想吐了:

比如从n=1,2,3,4我们推测。

当n=奇数时A赢定了。

当n=偶数时,如可以分为n/2的两个一摸一样的堆。比如(x,x,y,y,z,z)=>(x,y,z)+(x,y,z)。

时A也死定了。

而其它情况A就赢定了。


#include<iostream>#include<algorithm>#define max(a,b) (a>b?a:b)#define min(a,b) (a<b?a:b)using namespace std;const int N=105;int n;int num[N];int main(){while(scanf("%d",&n),n){memset(num,0,sizeof(num));int a;for(int i=1;i<=n;i++){scanf("%d",&a);num[a]++;}if(n%2){printf("1\n");continue;}bool flag=true;for(int i=1;i<=100&&flag;i++){if(num[i]%2){printf("1\n");flag=false;}}if(flag)printf("0\n");}return 0;}