您的位置:首页 > 其它

白书 博弈学习

2016-07-20 16:42 239 查看
nim博弈 n堆火柴,每堆有若干个火柴,两人轮流拿,每次可以选择一堆至少拿一个,也可以整堆拿走,无法拿的人输。

每堆火柴的个数异或和==0,先手输,否则先手赢。

http://acm.hust.edu.cn/vjudge/problem/32746 UVA11859

题意:给2维矩阵,每次可以选择矩阵的一行中的1个或多个大于1的整数,把他们每个数都变成真因子。 12可以变1 2 3 4 6.

解法: 等价于拿掉一个或者多个素因子,一行对应一堆火柴,每个数每个素因子看成一个火柴,即nim博弈。

#include<bits/stdc++.h>
#define mt(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=1e4+10;
int a[64][64];
char answer[2][8]={"NO","YES"};
vector<int> prime;
bool is[M];
int n,m;
void init(){
mt(is,0);
for(int i=2;i*i<M;i++){
if(is[i]) continue;
for(int j=i*i;j<M;j+=i){
is[j]=true;
}
}
prime.clear();
for(int i=2;i<M;i++){
if(is[i]) continue;
prime.push_back(i);
}
//    printf("%d",prime[prime.size()-1]);
}
int solve(){
int nim=0;
for(int i=0;i<n;i++){
int sum=0;
for(int j=0;j<m;j++){
for(int k=0;k<prime.size();k++){
if(prime[k]>a[i][j]) continue;
while(a[i][j]%prime[k]==0){
sum++;
a[i][j]/=prime[k];
}
}
}
nim^=sum;
}
return nim!=0;
}
int main(){
init();
int t;
while(~scanf("%d",&t)){
int cas=1;
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%d",&a[i][j]);
}
}
printf("Case #%d: %s\n",cas++,answer[solve()]);
}
}
return 0;
}


View Code

end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: