ZOJ1039
2016-01-25 11:10
295 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=39
记忆化搜索。这个题也相当郁闷,开始用f[i][j]表示第 i 次选择时 j 是不是必胜数,如果选择 j 后没有必胜数,那么 j 就是必胜数,反之不是必胜数,用DFS(i, j)来判断,总是不对,郁闷死了。后来看题解,用二进制状态压缩,于是改成二进制状态压缩,搜索的方式也改成和题解一样的,只是对于除去非法数字的方法不同,但仍然是错,恶心。
后来还是看题解。用二进制表示,从低位到高位,分别表示1到20是否在集合中。要判断一个数 j 是不是在集合中,只要&一下2^j就就可以了,结果位1,则在集合中,否则不在集合中。只是对于除去非法数字的方法没有看懂,郁闷。
记忆化搜索。这个题也相当郁闷,开始用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; } }
后来还是看题解。用二进制表示,从低位到高位,分别表示1到20是否在集合中。要判断一个数 j 是不是在集合中,只要&一下2^j就就可以了,结果位1,则在集合中,否则不在集合中。只是对于除去非法数字的方法没有看懂,郁闷。
#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; } }
相关文章推荐
- jQuery.validate.js扩展-手机号、固话校验,数字大小比较
- 通用大型网站页面静态化解决方案
- 倒计时
- Mac - NSView不能保证subview的z轴顺序
- html mailto
- FFmpeg - C++中使用ffmpeg库
- HDU 5591 ZYB's Game(博弈水题)
- Notification的使用
- Codeforces Round #340 (Div. 2) by komendart
- 《JAVA与模式》之简单工厂模式
- 月光博客: 个人用户如何安全地选择软件
- learn python the hard way(笨办法学python) 练习40 类的用法
- c#异常处理机制
- Android中的SharedPreferences存储数据方式
- linux修改hostname
- java基础篇--04<java基础类库>
- 在python3.3后urllib2已经不能再用,只能用urllib.request来代替
- OOP (Objects and Classes )
- FreeRTOS系列第14篇---FreeRTOS任务通知
- java中文乱码解决之道(九)—–总结