HDU 3980 Paint Chain 博弈 SG函数
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
Aekdycoin and abcdxyzk are playing a game. They get a circle chain with some beads. Initially none of the beads is painted. They take turns to paint the chain. In Each turn one player must paint a unpainted beads. Whoever is unable to paint in his turn lose the game. Aekdycoin will take the first move.
Now, they thought this game is too simple, and they want to change some rules. In each turn one player must select a certain number of consecutive unpainted beads to paint. The other rules is The same as the original. Who will win under the rules ?You may assume that both of them are so clever.
Input
First line contains T, the number of test cases. Following T line contain 2 integer N, M, indicate the chain has N beads, and each turn one player must paint M consecutive beads. (1 <= N, M <= 1000)
Output
For each case, print "Case #idx: " first where idx is the case number start from 1, and the name of the winner.
Sample Input
2
3 1
4 2
Sample Output
Case #1: aekdycoin
Case #2: abcdxyzk
-
题意:长度为n的环,每次操作取m个连续的块染色,aek…先手,轮流操作,不能继续操作的人输。
-
分析:长度为n,第一个人涂色之后就把环变成了一个长度为 n-m 的链了,局面由一个n变为 x , m, n - m - x,其中m是被染色完全的,所以变成了两个长度为 x 和 n-x-m 子游戏了。由 SG 定理,SG(n)=SG(x)^SG(n-x-m)。再由 SG 函数的定义式 SG[u]=mex(seg[v])。
-
代码:
const int SZ=1e3+5;
int sg[SZ];
int n,m;
int mex(int n){
if (sg[n]!=-1) return sg[n];
if (n < m) return sg[n] = 0;
int vis[SZ];
memset(vis, 0, sizeof vis);
for (int i = 0; i + m <=n; i++) {
if (sg[i] == -1) sg[i] = mex(i);
if (sg[n - i - m] == -1) sg[n - i - m] = mex(n - i - m);
vis[sg[i] ^ sg[n - i- m]] = 1;
}
for (int i = 0;; i++)
if (vis[i] == 0) {
sg[n] = i;
break;
}
return sg[n];
}
int main()
{
int T,cas = 0;
scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&m);
printf("Case #%d: ",++cas);
memset(sg,-1,sizeof sg);
if (m > n) puts("abcdxyzk");
else if (m == n) puts("aekdycoin");
else {
n -= m;
puts(mex(n) ? "abcdxyzk" : "aekdycoin");
}
}
return 0;
}
HDU 4778 Gems Fight 博弈 dp状压
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 327680/327680 K (Java/Others)
Problem Description
Alice and Bob are playing “Gems Fight!”:
There are Gems of G different colors , packed in B bags. Each bag has several Gems. G different colors are numbered from color 1 to color G.
Alice and Bob take turns to pick one bag and collect all the Gems inside. A bag cannot be picked twice. The Gems collected are stored in a shared cooker.
After a player ,we name it as X, put Gems into the cooker, if there are S Gems which are the same color in the cooker, they will be melted into one Magic Stone. This reaction will go on and more than one Magic Stone may be produced, until no S Gems of the same color remained in that cooker. Then X owns those new Magic Stones. When X gets one or more new Magic Stones, he/she will also get a bonus turn. If X gets Magic Stone in a bonus turn, he will get another bonus turn. In short,a player may get multiple bonus turns continuously.
There will be B turns in total. The goal of “Gems Fight!” is to get as more Magic Stones than the opponent as possible.
Now Alice gets the first turn, and she wants to know, if both of them act the optimal way, what will be the difference between the number of her Magic Stones and the number of Bob’s Magic Stones at the end of the game.
Input
There are several cases(<=20).
In each case, there are three integers at the first line: G, B, and S. Their meanings are mentioned above.
Then B lines follow. Each line describes a bag in the following format:
n c1 c2 … cn
It means that there are n Gems in the bag and their colors are color c1,color c2…and color cn respectively.
0<=B<=21, 0<=G<=8, 0<n<=10, S < 20.
There may be extra blank lines between cases. You can get more information from the sample input.
The input ends with G = 0, B = 0 and S = 0.
Output
One line for each case: the amount of Alice’s Magic stones minus the amount of Bob’s Magic Stones.
Sample Input
3 4 3
2 2 3
2 1 3
2 1 2
3 2 3 1
3 2 2
3 2 3 1
3 1 2 3
0 0 0
Sample Output
3
-3
-
题意:B个包裹,Alice和Bob依次轮流选,放在一起,每个包裹里面有bi个不同颜色的宝石,当某人新放入一个包裹的宝石的时候,若有同色宝石个数大于等于S,即可合成一个魔法石,同时作为奖励他可以获得额外一次选包裹。问最后Alice比Bob的魔法石多几个?
-
分析:
- 定义局面:二进制压缩状态,用0/1表示某个包裹被选了/未被选。
- 定义状态:dp[i]表示状态为i时,先手的收益 减去 后手的收益。
- 转移方程与博弈状态(先手\后手):
转移方程: dp[i] = max(dp[i] , dp[k] + get(i,k))
k为状态i的前一个状态,即少取一个包裹,get(i,k)为两个状态之间的魔法石个数。
若get(i,k)为0,则先手后手顺序颠倒,此时
dp[i] = max(dp[i], - dp[k])
博弈上理解就是,若没有奖励的额外机会,那么先手变后手,dp[]表示的差值取反就与之对应。
-
代码:
const int SZ=1e3+5;
int c[22][20];
int dp[1<<22],cooker[20],tmp[20];
int main()
{
int G,B,S;
while (scanf("%d%d%d",&G,&B,&S) == 3) {
if (G + B + S == 0) break;
for (int i = 0; i < B; i++) {
int n, x;
scanf("%d",&n);
for (int j = 1; j <= n; j++) {
scanf("%d",&x);
c[i][x] ++;
}
}
dp[0] = 0;
int V = (1 << B);
for (int i = 1; i < V; i++) {
dp[i] = -INF;
memset(cooker, 0, sizeof cooker);
for (int j = 0; j < B; j++)
if ((i & (1 << j)) == 0) {
for (int k = 1; k <= G; k++) {
cooker[k] += c[j][k];
cooker[k] %= S;
}
//int t = i - (1 << j);
//dp[i] = max(dp[i], )
}
for (int j = 0; j < B; j++) {
if (i & (1 << j)) {
for (int k = 1; k <= G;k++)
tmp[k] = cooker[k];
int get = 0;
for (int k = 1; k <= G;k++) {
tmp[k] += c[j][k];
get += tmp[k] / S;
tmp[k] %= S;
}
if (get) dp[i] = max(dp[i],dp[i ^ (1 << j)] + get);
else dp[i] = max(dp[i], - dp[i ^ (1 << j)]);
}
}
}
memset(c, 0 ,sizeof c);
printf("%d\n",dp[V - 1]);
}
return 0;
}
HDU 4764 Stone 巴什博弈
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Problem Description
Tang and Jiang are good friends. To decide whose treat it is for dinner, they are playing a game. Specifically, Tang and Jiang will alternatively write numbers (integers) on a white board. Tang writes first, then Jiang, then again Tang, etc… Moreover, assuming that the number written in the previous round is X, the next person who plays should write a number Y such that 1 <= Y - X <= k. The person who writes a number no smaller than N first will lose the game. Note that in the first round, Tang can write a number only within range [1, k] (both inclusive). You can assume that Tang and Jiang will always be playing optimally, as they are both very smart students.
Input
There are multiple test cases. For each test case, there will be one line of input having two integers N (0 < N <= 10^8) and k (0 < k <= 100). Input terminates when both N and k are zero.
Output
For each case, print the winner’s name in a single line.
Sample Input
1 1
30 3
10 2
0 0
Sample Output
Jiang
Tang
Jiang
- 题意:T和J,轮流写数字,前面一个人写x那么后面一个人写y 要使得1<=y-x<=k. 写的数>=n则输。
- 巴什博弈:必败点是 (n - 1) % ( k + 1) = 0。因为n - 1状态是必胜态,若(n-1)是(k + 1)的倍数,无论先手是多少,后手都可以取走k + 1剩下部分,最后后手到达(n - 1)必胜态。
- 巴什博弈百度百科,click here.
- 代码
int main(){
int n,k;
while(scanf("%d%d",&n,&k) == 2){
if (n + k == 0) break;
if ((n - 1) % (k + 1) != 0)
puts("Tang");
else puts("Jiang");
}
return 0;
}
HDU 4778 Mine Nim博弈
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Problem Description
Have you ever played a game in Windows: Mine?
This game is played on a n*m board, just like the Pic(1)
On the board, Under some grids there are mines (represent by a red flag). There are numbers ‘A(i,j)’ on some grids means there’re A(i,j) mines on the 8 grids which shares a corner or a line with gird(i,j). Some grids are blank means there’re no mines on the 8 grids which shares a corner or a line with them.
At the beginning, all grids are back upward.
In each turn, Player should choose a back upward grid to click.
If he clicks a mine, Game over.
If he clicks a grid with a number on it , the grid turns over.
If he clicks a blank grid, the grid turns over, then check grids in its 8 directions.If the new grid is a blank gird or a grid with a number,it will be clicked too.
So If we click the grid with a red point in Pic(1), grids in the area be encompassed with green line will turn over.
Now Xiemao and Fanglaoshi invent a new mode of playing Mine. They have found out coordinates of all grids with mine in a game. They also find that in a game there is no grid will turn over twice when click 2 different connected components.(In the Pic(2), grid at (1,1) will turn over twice when player clicks (0,0) and (2,2) , test data will not contain these cases).
Then, starting from Xiemao, they click the grid in turns. They both use the best strategy. Both of them will not click any grids with mine, and the one who have no grid to click is the loser.
Now give you the size of board N, M, number of mines K, and positions of every mine Xi,Yi. Please output who will win.
Input
Multicase
The first line of the date is an integer T, which is the number of the text cases. (T<=50)
Then T cases follow, each case starts with 3 integers N, M, K indicates the size of the board and the number of mines.Then goes K lines, the ith line with 2 integer Xi,Yi means the position of the ith mine.
1<=N,M<=1000 0<=K<=N*M 0<=Xi<N 0<=Yi<M
Output
For each case, first you should print "Case #x: ", where x indicates the case number between 1 and T . Then output the winner of the game, either ”Xiemao” or “Fanglaoshi”. (without quotes)
Sample Input
2
3 3 0
3 3 1
1 1
Sample Output
Case #1: Xiemao
Case #2: Fanglaoshi
-
题意:扫雷游戏,已知雷的数量和位置,每人一次要点击一个块,如果有数字就只能点开这一个块,如果没有数字,就可以点开所有空白格和其外层带数字的一圈。没格子可点的会输。
-
题目分析:首先需要bfs,找出所有空白块以及周围相连带数字的块,以及单个带数字的块,联通的空白块算做一个。之后是博弈的过程,对于有空白块的堆,每次可以去一个或者全取出。一个数字的sg值显然是mex{0} = 1,对于有空白块的,有两种子状态,点一个数字,或者点掉整个块,所以sg值是mex{0,1} = 2 ,mex{0, 2} = 1,打表就是1和2循环的。之后求所有堆的sg值异或和即可。
-
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e3+10;
int n,m,k,tot;
int ans;
int a[MAXN][MAXN],mark[MAXN][MAXN];
int gx[] =