最开始DP思路大方向是对的,但是一直苦于状态不知道怎么表示。
略览下题解思路,状态压缩,用是经常用,之前也联系过,实战上还是显出生疏了,对这么常用的技巧竟然一时没想起来
真正写代码的时候也磕磕绊绊debug了很久,一边怕数组越界,一边担心数组开爆,但最后数组还是开小了,RUNTIMEERROR好久
还是差的很多,继续提升吧
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int maxn= 25;
const int maxs= 21;
int a[maxn];
bool ck[maxn];
bool dv[(1<<maxs)+5], vis[(1<<maxs)+5];
int n;
bool DP(int st)
{
if (vis[st]){
return dv[st];
}
int lose= 1;
for (int i= 0; i< n && lose; ++i){
if (!ck[a[i]]){
continue;
}
int t_st= st ^ (1<<a[i]);
ck[a[i]]= 0;
int drop= 0;
drop|= (1<<i);
for (int j= i+1; j< n; ++j){
if (!ck[a[j]]){
continue;
}
int flag= 1;
if (0== a[j]%a[i]){
flag= 0;
}
for (int p= a[j]-a[i]; p> 1 && flag; p-= a[i]){
if (!ck[p]){
flag= 0;
}
}
if (!flag){
t_st^= (1<<a[j]);
ck[a[j]]= 0;
drop|= (1<<j);
}
}
if (!DP(t_st)){
lose= 0;
}
vis[t_st]= 1;
for (int k= i; k< n; ++k){
if (drop & (1<<k)){
ck[a[k]]= 1;
}
}
}
vis[st]= 1;
return dv[st]= lose ? 0 : 1;
}
int main(int argc, char const *argv[])
{
int kase= 0;
while (~scanf("%d" ,&n) && n){
vector<int> ans;
memset(ck, 0 ,sizeof(ck));
memset(vis, 0, sizeof(vis));
int st= 0;
for (int i= 0; i< n; ++i){
scanf("%d", a+i);
ck[a[i]]= 1;
st|= (1<<a[i]);
}
sort(a, a+n);
dv[0]= 0;
vis[0]= 1;
for (int i= 0; i< n; ++i){
int t_st= st ^ (1<<a[i]);
int drop= 0;
ck[a[i]]= 0;
drop|= (1<<i);
for (int j= i+1; j< n; ++j){
int flag= 1;
if (0== a[j]%a[i]){
flag= 0;
}
for (int p= a[j]-a[i]; p> 1 && flag; p-= a[i]){
if (!ck[p]){
flag= 0;
}
}
if (!flag){
t_st^= (1<<a[j]);
ck[a[j]]= 0;
drop|= 1<<j;
}
}
if (!DP(t_st)){
ans.push_back(a[i]);
}
vis[t_st]= 1;
for (int k= i; k< n; ++k){
if (drop & (1<<k)){
ck[a[k]]= 1;
}
}
}
printf("Test Case #%d
", ++kase);
if (ans.empty()){
printf("There's no winning move.");
}
else{
printf("The winning moves are:");
int sz= ans.size();
for (int i= 0; i< sz; ++i){
printf(" %d", ans[i]);
}
}
putchar('
');
putchar('
');
}
return 0;
}