题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=39
记忆化搜索。这个题也相当郁闷,开始用f[i][j]表示第 i 次选择时 j 是不是必胜数,如果选择 j 后没有必胜数,那么 j 就是必胜数,反之不是必胜数,用DFS(i, j)来判断,总是不对,郁闷死了。后来看题解,用二进制状态压缩,于是改成二进制状态压缩,搜索的方式也改成和题解一样的,只是对于除去非法数字的方法不同,但仍然是错,恶心。
#include<iostream> #include<cstring> using namespace std; int f[1<<21]; bool g[1<<21]; bool used[25]; void Chenge(int i) { int j = i; while (j <= 20) { used[j] = true; //for (int k=2; k<=20; k++) // if (used[k] && k+j <=20) // used[k+j] = true; j += i; } } void Back(bool tmp[]) { for (int i=0; i<25; i++) used[i] = tmp[i]; } int work() { int now = 0; for (int i=1; i<=20; i++) if (!used[i]) now += 1<<i; return now; } int DFS() { int now = work(); if (g[now]) return f[now]; g[now] = true; f[now] = 0; bool tmp[25]; for (int i=0; i<25; i++) tmp[i] = used[i]; for (int i=2; i<=20; i++) if (!used[i]) { Chenge(i); int New = work(); int x = DFS(); if (x == 0) f[now] += (1<<(i-1)) ; Back(tmp); } return f[now]; } int main() { int t; int k = 0; cin>>t; while (t--) { k++; memset(used,true,sizeof(used)); memset(f,false,sizeof(f)); memset(g,false,sizeof(g)); int a; cin>>a; for (int i=0; i<a; i++) { int x; cin>>x; used[x] = false; } int ans = 0; cout<<"Scenario #"<<k<<":"<<endl; if (!(ans = DFS())) { cout<<"There is no winning move."<<endl; continue; } cout<<"The winning moves are:"; for (int i=1; i<=20; i++) { if (ans % 2 == 1) cout<<' '<<i; ans >>= 1; if (ans == 0) break; } cout<<"."<<endl; cout<<endl; } }
#include<iostream> #include<cstring> using namespace std; int f[1<<21]; int mask[1<<21]; int DFS(int num) { if (f[num] == -1) { f[num] = 0; for (int i=2; i<=20; i++) if ((num & mask[i]) != 0) { int tmp = num; int j = i; while (j<=20) { int buf = (((num | 1) << j) | (mask[j]-1)); tmp &= buf; j += i; } int x = DFS(tmp); if (x == 0) f[num] += mask[i]; } } return f[num]; } int main() { int t; int k = 0; cin>>t; while (t--) { k++; memset(f,255,sizeof(f)); for (int i=1; i<=20; i++) mask[i+1] = 1<<i; int a = 0,n; cin>>n; for (int i=0; i<n; i++) { int x; cin>>x; a |= mask[x]; } int ans = DFS(a); cout<<"Scenario #"<<k<<":"<<endl; if (ans == 0) { cout<<"There is no winning move."<<endl; cout<<endl; continue; } cout<<"The winning moves are:"; for (int i=1; i<=20; i++) { if (ans % 2 == 1) cout<<' '<<i; ans >>= 1; if (ans == 0) break; } cout<<"."<<endl; cout<<endl; } }