hdu1846
1、 本游戏是一个二人游戏;
2、 有一堆石子一共有n个;
3、 两人轮流进行;
4、 每走一步可以取走1…m个石子;
5、 最先取光石子的一方为胜;
如果游戏的双方使用的都是最优策略,请输出哪个人能赢。
每组测试数据占一行,包含两个整数n和m(1<=n,m<=1000),n和m的含义见题目描述。
#include<iostream> #include<cstdio> using namespace std; int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); if(m >= n) printf("first\n"); else{ if(n%(m+1) == 0) printf("second\n"); else printf("first\n"); } } return 0; }
hdu1847
大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此。当然,作为在考场浸润了十几载的当代大学生,Kiki和Cici更懂得考前的放松,所谓“张弛有道”就是这个意思。这不,Kiki和Cici在每天晚上休息之前都要玩一会儿扑克牌以放松神经。
“升级”?“双扣”?“红五”?还是“斗地主”?
当然都不是!那多俗啊~
作为计算机学院的学生,Kiki和Cici打牌的时候可没忘记专业,她们打牌的规则是这样的:
1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
假设Kiki和Cici都是足够聪明(其实不用假设,哪有不聪明的学生~),并且每次都是Kiki先抓牌,请问谁能赢呢?
当然,打牌无论谁赢都问题不大,重要的是马上到来的CET-4能有好的状态。
Input
如果Kiki能赢的话,请输出“Kiki”,否则请输出“Cici”,每个实例的输出占一行。
#include<cstdio> #include<iostream> #include<cmath> #include<set> using namespace std; int mex(set<int>&s){ int a = 0; if(s.count(a)) a++; return a; } int main(){ int i; int d[15]; int numd = 10; for(int i = 0;i < 10;i++){ d[i] = pow(2,i); } int n; while(scanf("%d",&n) != EOF){ int sg[1010] = {0}; for(int i = 1;i <= n;i++){ set<int>s; for(int j = 0;j < numd;j++){ if(i - d[j] < 0) continue; s.insert(sg[i-d[j]]); } sg[i] = mex(s); } if(sg[n] == 0){ cout << "Cici" << endl; } else cout <<"Kiki" << endl; } }
F(1)=1;
F(2)=2;
F(n)=F(n-1)+F(n-2)(n>=3);
所以,1,2,3,5,8,13……就是菲波那契数列。
在HDOJ上有不少相关的题目,比如1005 Fibonacci again就是曾经的浙江省赛题。
今天,又一个关于Fibonacci的题目出现了,它是一个小游戏,定义如下:
1、 这是一个二人游戏;
2、 一共有3堆石子,数量分别是m, n, p个;
3、 两人轮流走;
4、 每走一步可以选择任意一堆石子,然后取走f个;
5、 f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量);
6、 最先取光所有石子的人为胜者;
假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。奇异态先手必输!
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<set> #include<cstring> using namespace std; const int N = 1010; int sg[N]; bool Hash[N]; void sg_solve(int *s,int t){ ///N求解范围 S[]数组是可以每次取的值,t是s的长度。下标从0开始 int i,j; memset(sg,0,sizeof(sg)); for(i=1; i<N; i++){ memset(Hash,0,sizeof(Hash)); for(j=0; j<t; j++) if(i - s[j] >= 0) Hash[sg[i-s[j]]] = 1; for(j=0; j<N; j++) if(!Hash[j]) break; sg[i] = j; } } int main(){ int n,m,p,res; int s[100] = {1,2}; int nums = 2; while(1){ s[nums] = s[nums-1] + s[nums-2]; if(s[nums] > 1000) break; nums++; } sg_solve(s,nums); while(scanf("%d%d%d",&n,&m,&p) != EOF){ if(n + m + p == 0) break; res = sg[n]^sg[m]^sg[p]; if(res == 0) printf("Nacci\n"); else printf("Fibo\n"); } return 0; }
hdu1849
Rabbit and Grass(未变形的裸nim博弈)
说是下棋,其实只是一个简单的小游戏而已,游戏的规则是这样的:
1、棋盘包含1*n个方格,方格从左到右分别编号为0,1,2,…,n-1;
2、m个棋子放在棋盘的方格上,方格可以为空,也可以放多于一个的棋子;
3、双方轮流走棋;
4、每一步可以选择任意一个棋子向左移动到任意的位置(可以多个棋子位于同一个方格),当然,任何棋子不能超出棋盘边界;
5、如果所有的棋子都位于最左边(即编号为0的位置),则游戏结束,并且规定最后走棋的一方为胜者。
对于本题,你不需要考虑n的大小(我们可以假设在初始状态,棋子总是位于棋盘的适当位置)。下面的示意图即为一个1*15的棋盘,共有6个棋子,其中,编号8的位置有两个棋子。
大家知道,虽然偶尔不够浪漫,但是Rabbit和Grass都是冰雪聪明的女生,如果每次都是Rabbit先走棋,请输出最后的结果。
如果Rabbit能赢的话,请输出“Rabbit Win!”,否则请输出“Grass Win!”,每个实例的输出占一行。
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<set> #include<cstring> using namespace std; int a[1010]; int main(){ int n,res; while(scanf("%d",&n)){ res = 0; if(n == 0) break; for(int i = 0;i < n;i++){ scanf("%d",&a[i]); res = res^a[i]; } if(res == 0) printf("Grass Win!\n"); else printf("Rabbit Win!\n"); } return 0; }
hdu1850
Being a Good Boy in Spring Festival
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8434 Accepted Submission(s): 5172
一年在外 父母时刻牵挂
春节回家 你能做几天好孩子吗
寒假里尝试做做下面的事情吧
陪妈妈逛一次菜场
悄悄给爸爸买个小礼物
主动地 强烈地 要求洗一次碗
某一天早起 给爸妈用心地做回早餐
如果愿意 你还可以和爸妈说
咱们玩个小游戏吧 ACM课上学的呢~
下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
现在我们不想研究到底先手为胜还是为负,我只想问大家:
——“先手的人如果想赢,第一步有几种选择呢?”
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<set> #include<cstring> using namespace std; int main(){ int n,sum,res; int a[110]; while(scanf("%d",&n) != EOF){ if(n == 0) break; sum = 0; for(int i = 0;i < n;i++){ scanf("%d",&a[i]); sum = sum^a[i]; } if(sum == 0){ printf("0\n"); } else{ res = 0; for(int i = 0;i < n;i++){ if((sum^a[i]) <= a[i]) res++; } printf("%d\n",res); } } return 0; }
hdu1536 典型nim博弈加sg函数!!!典型哦
S-Nim
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8918 Accepted Submission(s): 3726
The starting position has a number of heaps, all containing some, not necessarily equal, number of beads.
The players take turns chosing a heap and removing a positive number of beads from it.
The first player not able to make a move, loses.
Arthur and Caroll really enjoyed playing this simple game until they recently learned an easy way to always be able to find the best move:
Xor the number of beads in the heaps in the current position (i.e. if we have 2, 4 and 7 the xor-sum will be 1 as 2 xor 4 xor 7 = 1).
If the xor-sum is 0, too bad, you will lose.
Otherwise, move such that the xor-sum becomes 0. This is always possible.
It is quite easy to convince oneself that this works. Consider these facts:
The player that takes the last bead wins.
After the winning player's last move the xor-sum will be 0.
The xor-sum will change after every move.
Which means that if you make sure that the xor-sum always is 0 when you have made your move, your opponent will never be able to win, and, thus, you will win.
Understandibly it is no fun to play a game when both players know how to play perfectly (ignorance is bliss). Fourtunately, Arthur and Caroll soon came up with a similar game, S-Nim, that seemed to solve this problem. Each player is now only allowed to remove a number of beads in some predefined set S, e.g. if we have S =(2, 5) each player is only allowed to remove 2 or 5 beads. Now it is not always possible to make the xor-sum 0 and, thus, the strategy above is useless. Or is it?
your job is to write a program that determines if a position of S-Nim is a losing or a winning position. A position is a winning position if there is at least one move to a losing position. A position is a losing position if there are no moves to a losing position. This means, as expected, that a position with no legal moves is a losing position.
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<set> #include<cstring> using namespace std; const int N = 10005;//每堆个数的最大值 int sg[N],a[105]; bool Hash[N]; void sg_solve(int *s,int t){ ///N求解范围 S[]数组是可以每次取的值,t是s的长度。下标从0开始 int i,j; memset(sg,0,sizeof(sg)); for(i=1; i<N; i++){ memset(Hash,0,sizeof(Hash)); for(j=0; j<t; j++) if(i - s[j] >= 0) Hash[sg[i-s[j]]] = 1; for(j=0; j<N; j++) if(!Hash[j]) break; sg[i] = j; } } int main(){ int n,n2,n3,res,cur; int s[110]; while(scanf("%d",&n)){ if(n == 0) break; for(int i = 0;i < n;i++){ scanf("%d",&s[i]); } sg_solve(s,n); scanf("%d",&n2); while(n2--){ scanf("%d",&n3); res = 0; while(n3--){ scanf("%d",&cur); res = res^sg[cur]; } if(res == 0)printf("L"); else printf("W"); } printf("\n"); } return 0; }
hdu1907 变形的!裸nim博弈,变成取完输态(判断是否为充裕堆)
John
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 5617 Accepted Submission(s): 3252
Both of players are using optimal game strategy. John starts first always. You will be given information about M&Ms and your task is to determine a winner of such a beautiful game.
Constraints:
1 <= T <= 474,
1 <= N <= 47,
1 <= Ai <= 4747
#include<iostream> #include<cstdio> using namespace std; //异或结果为0,先手必输 //如果是变形的话 int a[50]; int n; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); int res = 0; int book = 0; for(int i = 0;i < n;i++){ scanf("%d",&a[i]); res = res^a[i]; if(a[i] > 1) book++; } if((res == 0&&book)||(res == 1&&book == 0))///偶数堆 每堆1个 和 奇异态(先手输 cout << "Brother" << endl; else cout << "John" << endl; } return 0; }