太开心了,这是我第一道自己想出来的利用二进制的做法把博弈做出来的,good!!!
题意:一般的博弈,给你n堆,一次只能取一堆中的任意个,求先手若想获胜有多少可行的第一步
分析:当所有堆的异或值为0的话,则必败,所以现在要做的就是如何让对手面对的局势是异或值为0
转换为2进制,5,7,9只能够变9才能是所有的数的异或为0
5 101 101 变010
7 111 1101 或他变1010
9 ^ 1001 变成0010 111 或他变001
1000
依次类推:全部转换为二进制,从最高一位开始比较,若到达每一二进制位的异或不为0,该位含有几个1,就表示可以变化几次
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; bool cmp(int &a,int &b) { return a<b; } int main() { int ans,n,j; int a[110]; int sum[33]; while(scanf("%d",&n) && n) { ans=0; memset(sum,0,sizeof(sum)); for (int i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n,cmp); for (j=0;j<32;j++)//二进制的位数是32 { for (i=0;i<n;i++) { sum[j]+=a[i]&1;//判断该位是否为1 a[i]>>=1; } } for (i=31;i>=0;i--) if(sum[i]%2!=0) break;//当为偶数的时候异或=0 if(i!=-1) printf("%d\n",sum[i]); else printf("0\n"); } return 0; }
别人的思想
View Code
/* 先求总和的异或值,若存在的状态非为必败点,则必定存在一堆的改变其数值导致整个局势为必败局势, 所以说只要找出那一堆的数字大于需要完成达到必败局势所需要填补的数(也就是大于该数字对与总异或值的异或后的结果) 就可以了 */ #include<stdio.h> int main() { int T,i; int a[100]; while(scanf("%d",&T) && T) { int sum=0; int cnt=0; for (i=0;i<T;i++) { scanf("%d",&a[i]); sum^=a[i];//求总异或和 } for (i=0;i<T;i++) a[i]>(sum^a[i]) ? cnt++:0; printf("%d\n",cnt); } return 0; }