这个题算DP吧,但用记忆化搜索和位运算就可以过~
注意状态的压缩和记忆,题意搞了半天,后来参考了网上高人的题解和代码才搞懂题意,主要是线性表示那~
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=21;
int n,pos,a[maxn],ans[maxn],cnt;
int dp[2097158];
bool DFS(int posa,int posb)
{
if(posb==0)
return 0;
if(dp[posb]!=-1)
return dp[posb];
int ita,itb;
for(int i=0;i<n;i++)
{
ita=posa;
itb=posb;
if(itb&(1<<i))
{
for(int j=0;j+a[i]<21;j++)
if(ita&(1<<j))
ita|=1<<(j+a[i]);
for(int j=0;j<n;j++)
if(itb&(1<<j)&&(ita&(1<<a[j])))
itb^=1<<j;
if(!DFS(ita,itb))
return dp[posb]=1;
}
}
return dp[posb]=0;
}
int main()
{
int cas=1;
while(scanf("%d",&n)&&n)
{
memset(dp,-1,sizeof(dp));
cnt=0;
pos=(1<<21)-3;
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
pos^=1<<a[i];
}
sort(a,a+n);
for(int i=0;i<n;i++)
{
int ita=pos;
int itb=(1<<n)-1;
for(int j=0;j+a[i]<21;j++)
if(ita&(1<<j))
ita|=1<<(j+a[i]);
for(int j=0;j<n;j++)
if(ita&(1<<a[j]))
itb^=1<<j;
if(!DFS(ita,itb))
{
dp[ita]=1;
ans[cnt++]=a[i];
}
}
printf("Test Case #%d\n",cas++);
if(!cnt)
{
printf("There's no winning move.\n\n");
continue;
}
printf("The winning moves are:");
for(int i=0;i<cnt;i++)
printf(" %d",ans[i]);
printf("\n\n");
}
return 0;
}