您的位置:首页 > 其它

SG-分石子游戏

2014-05-19 19:20 471 查看


分石子问题

时间限制:2000 ms  |  内存限制:65535 KB
难度:6

描述

闲来无事,zyc发明了一种游戏,叫分石子游戏,初始有D堆石子,每堆石子的数量已知。

两个人轮流分石子,可以选取这D堆石子中的任意一堆,然后把选中的这堆石子分成M堆(每堆石子数量都必须大于0),现在石子的堆数将变成D+M-1堆,对方就可以在这D+M-1堆石子中任意选一堆分成M堆,依次分下去,直到某人无法执行这种操作时则无法执行操作的人输掉了这场游戏。

如果玩游戏的双方都非常聪明,现在给你一个初始状态,请你判断先分石子的人是会取胜还是会失败。

输入第一行是一个整数T,表示测试数据的组数(T<=10)

每组测试数据的第一行是两个整数D,M(0<D<100,2<=M<=7)

随后的一行有D个正整数Ni(Ni<100),表示每堆石子的初始数量。
输出如果先分石子的人获胜则输出Win

否则输出Lose
样例输入
2
1 3
5
2 3
5 6


样例输出
Win
Lose


计算sg函数,找规律:

#include <iostream>
#include <string.h>
using namespace std;
#define maxn 100
int a[maxn];
int vis[maxn];
int sg[maxn];
int ed[maxn];
int mm;
int fun(int n,int m,int minn,int rt){//n为剩下的石子数,m为剩下待分堆数,minn为先拿出的个数(不一定是石子数,可能后面会增长),rt为以分的堆数
ed[rt]=minn;//第rt次分了minn这么一堆
if(m==1){
ed[rt]=n;//最后一次只能是剩下的n个为一堆
int temp=sg[ed[0]];
for(int i=1;i<=rt;i++){
temp^=sg[ed[i]];//所有的堆分完了,利用sg值 计算NIM值,当作此中分发的sg值
}
vis[temp]=1;
}else if(m*minn <=n){//还可以分
fun(n-minn, m-1, minn, rt+1);//就以minn为一堆,分出去
fun(n, m, minn+1, rt);//再拿出一部分给minn,还不确定当前堆的石子数目
}
}
int main(){
int n;
cin>>n>>mm;
int ma=0;
for(int i=0;i<n;i++){
cin>>a[i];
ma=max(ma,a[i]);
}
for(int i=0;i<mm;i++)sg[i]=0;sg[mm]=1;
for(int i=mm+1;i<=ma;i++){
memset(vis,0,sizeof(vis));
fun(i,mm,1,0);
for(int j=0;;j++){
if(!vis[j]){
sg[i]=j;
break;
}
}
}
int sum=0;
for(int i=0;i<n;i++)
sum^=sg[a[i]];
if(sum)cout<<"win"<<endl;
else cout<<"lose"<<endl;

return 0;}


化简

代码:

#include <cstdio>
using namespace std;

int main()
{
int T, d, m;
for (scanf("%d", &T); T--; ) {
int a, sum = 0;
scanf("%d%d", &d, &m);
for (int i = 0; i < d; i++) {
scanf("%d", &a);
sum ^= m == 2 ? a > 1 && a%2 == 0 : a >= m ? (a-1)/(m-1) : 0;
}
puts(sum ? "Win" : "Lose");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  博弈 SG函数 nyoj