题意:
2n个人围成一圈,编号为奇数的一队,编号为偶数的一队,轮流从原本S个石头的石堆进行拿石头操作
每个人可拿石头范围在[1,m[i]]内(m[i]表示第i个人最多能拿的石头数)
问先手(0所在的偶数队)能否取胜
分析:
dp[i][j]表示第i个人面对j个石头的局面 是否能胜(1/0)
只要有“败”的子状态就是胜态
如果子状态全为胜态则为败态
状态转移:
在dp[(i+1)%2n][j-x]中找败态(x ∈ [1,m[i]])
表示第i个人拿走x个石头,让下一个人(i+1)%2n面对j-x个石头的局面
记忆化搜索=-=
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
/*
dp[i][j]表示第i个人面对j个石头的局面 是否能胜
只要有“败”的子状态就是胜态
如果子状态全为胜态则为败态
状态转移:
在dp[(i+1)%2n][j-x]中找败态
表示第i个人拿走x个石头,让第(i+1)%2n个人面对j-x个石头的局面
记忆化搜索=-=
*/
int dp[22][1<<14];
int m[22];
int n,s;
int DP(int i,int j)
{
if (j == 0) return 1;//没有石头的局面为胜态
if (~dp[i][j]) return dp[i][j];
for (int x = 1;x <= m[i];++x)
{
if (j-x<0) break;
if (DP((i+1)%(2*n),j-x) == 0) return dp[i][j] = 1;
}
return dp[i][j] = 0;
}
int main()
{
while (cin>>n)
{
if (!n) break;
cin>>s;
for (int i = 0;i < 2*n;++i) cin>>m[i];
mem(dp,-1);
cout<<DP(0,s)<<endl;
}
return 0;
}
java:
//package acm.poj2068;
import java.util.*;
public class Main {
static int n , s;
static int dp[][] = new int[22][1<<14];
static int m[] = new int [22];
static void init(){
for (int i = 0;i <= 2*n;++i){
Arrays.fill(dp[i], -1);
}
}
static int DP(int i,int j){
if (j == 0) return 1;
if (dp[i][j]!=-1) return dp[i][j];
for (int x = 1;x <= m[i];++x){
if (j-x<0) break;
if (DP((i+1)%(2*n),j-x) == 0) return dp[i][j] = 1;
}
return dp[i][j] = 0;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
@SuppressWarnings("resource")
Scanner in = new Scanner(System.in);
while (in.hasNext()){
n = in.nextInt();
if (n == 0) break;
s = in.nextInt();
for (int i = 0;i < 2*n;++i){
m[i] = in.nextInt();
}
init();
System.out.println(DP(0,s));
}
}
}