题目描述
Christine and Matt are playing an exciting game they just invented: the Number Game. The rules of this game are as follows.
The players take turns choosing integers greater than 1. First, Christine chooses a number, then Matt chooses a number, then Christine again, and so on. The following rules restrict how new numbers may be chosen by the two players:
A number which has already been selected by Christine or Matt, or a multiple of such a number,cannot be chosen.
A sum of such multiples cannot be chosen, either.
If a player cannot choose any new number according to these rules, then that player loses the game.
Here is an example: Christine starts by choosing 4. This prevents Matt from choosing 4, 8, 12, etc.Let’s assume that his move is 3. Now the numbers 3, 6, 9, etc. are excluded, too; furthermore, numbers like: 7 = 3+4;10 = 2*3+4;11 = 3+2*4;13 = 3*3+4;… are also not available. So, in fact, the only numbers left are 2 and 5. Christine now selects 2. Since 5=2+3 is now forbidden, she wins because there is no number left for Matt to choose.
Your task is to write a program which will help play (and win!) the Number Game. Of course, there might be an infinite number of choices for a player, so it may not be easy to find the best move among these possibilities. But after playing for some time, the number of remaining choices becomes finite, and that is the point where your program can help. Given a game position (a list of numbers which are not yet forbidden), your program should output all winning moves.
A winning move is a move by which the player who is about to move can force a win, no matter what the other player will do afterwards. More formally, a winning move can be defined as follows.
A winning move is a move after which the game position is a losing position.
A winning position is a position in which a winning move exists. A losing position is a position in which no winning move exists.
In particular, the position in which all numbers are forbidden is a losing position. (This makes sense since the player who would have to move in that case loses the game.)
题目意思
这道题一开始让我觉得有点绕,总之应该正确的理解题目的意思。
1. winning move指的是可以让winning case转化为losing case的操作
2. winning case指的是存在winning move的状态
3. losing case指的是不存在winning move的状态
4. 特别的,如果没有数可以选择了,那么显然这是一个losing case
算法思路
- 个人觉得,这一题的状态之间的关系构成了一个二分图。
如果存在操作之后转化成了losing case, 那么这个状态就是一个winning case, 反之这个操作就是losing case. - 根据条件4,dp[0]=-1(没有数可以选择的情况下)
- 我们注意到,这一题最大的数也就20,所以可以使用状态压缩。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 20
#define MAX 2150000
int n;
int cas = 0;
int dp[MAX];
int gamePosition;
int ans[MAXN+1],len;
bool Dfs(int position, int cur)
{
int i;
position -= 1 << cur;
//delete the number that is multiple of current number
//or is the sum of two numbers
for(i=2;i+cur<=MAXN;i++){
if(position & (1 << (i+cur)) && !(position & (1 << i))){
position -= 1 << (i+cur);
}
}
if(dp[position] < 0){
return false;
}
else if(dp[position] > 0){
return true;
}
//search if there exsits a winning move
for(i=2;i<=MAXN;i++){
if(position & (1 << i) && !Dfs(position,i)){
dp[position] = 1;
return true;
}
}
dp[position] = -1;
return false;
}
int main()
{
freopen("input","r",stdin);
int i,a;
memset(dp,0,sizeof(dp));
dp[0] = -1;
while(scanf("%d",&n)!=EOF && n){
gamePosition = 0;
len = 0;
for(i=1;i<=n;i++){
scanf("%d",&a);
gamePosition += 1<<a;
}
for(i=2;i<=MAXN;i++){
if(gamePosition & (1<<i) && !Dfs(gamePosition,i)){
ans[len++] = i;
}
}
cas++;
printf("Test Case #%d\n",cas);
if(len > 0){
printf("The winning moves are:");
for(i=0;i<len;i++)
printf(" %d",ans[i]);
printf("\n");
}
else{
//if no winning move exsits, then it is a
//losing case
dp[gamePosition] = -1;
printf("There's no winning move.\n");
}
printf("\n");
}
return 0;
}