POJ1085 The Triangle War: 记忆化搜索
来源:互联网 发布:2016党章党规网络测试 编辑:程序博客网 时间:2024/06/05 06:30
根本不知道怎么下手,后面看了别人的博客:
http://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5846776
POJ 1085 The Triangle War
* 题目注意:这道题中对于线段是谁放置的不关心,只要自己放置的线段形成一个完整的三角形就是获得了一次奖励
* 题目分析:
* 这道题目是关于博弈的搜索题,这里使用动态规划的思想来做,而动态规划的关键是状态的表示和存储。
* 由于游戏的局面状态变化总是和线段是否放置相关,于是可以这样来表达和记录局面状态,用二进制形式表示
* 线段,2^i表示第i条线段(i从0开始),这样的话,局面状态state也可以用线段二进制的或运算结果来表示了,而且
* 满足:0<= state < 2^18 。
* 这里还需要注意的是状态表f[state]中记录的是对于当前局面state,某一方先走,然后双方都采取最优策略,最终双方
* 所拥有的新产生的三角形个数的差值
*/
* 题目注意:这道题中对于线段是谁放置的不关心,只要自己放置的线段形成一个完整的三角形就是获得了一次奖励
* 题目分析:
* 这道题目是关于博弈的搜索题,这里使用动态规划的思想来做,而动态规划的关键是状态的表示和存储。
* 由于游戏的局面状态变化总是和线段是否放置相关,于是可以这样来表达和记录局面状态,用二进制形式表示
* 线段,2^i表示第i条线段(i从0开始),这样的话,局面状态state也可以用线段二进制的或运算结果来表示了,而且
* 满足:0<= state < 2^18 。
* 这里还需要注意的是状态表f[state]中记录的是对于当前局面state,某一方先走,然后双方都采取最优策略,最终双方
* 所拥有的新产生的三角形个数的差值
*/
从这道题目中,可以看出动态规划表存储值的定义需要实现明确的。
还可以用启发式搜索,我还不怎么会,后面再来补充;
他的代码:
题目大意是2个人玩一种游戏,每次放1条边,如果生成了三角形,则归他所有给定一些初始的走法,问都以最优策略走谁最后拿的三角形多?很早做的,有点难度,详细注释dp,或者说是博弈//4448583_AC_485MS_1468K /********************************************************************** * Online Judge : POJ * Problem Title : Triangle War * ID : 1085 * Date : 12/3/2008 * Time : 8:23:54 * Computer Name : EVERLASTING-PC ***********************************************************************/ /* 线段使用二进制存储,2^i表示第i条线段的hash值 0<=state<2^18,二进制表示当前棋盘状态 f(state) 表示在state这个状态下,A先走,双方走法都是最优,最终A比B多得到的三角形个数 0<=i<18,记place(state,2^i)=t,则 f(state)=max { t -f(state|2^i) 当t=0 t +f(state|2^i) 当t>0 } */ #include<iostream> using namespace std; //储存组成每个三角形的线段hash值 int tri[9][3]= { {0x1,0x2,0x4}, {0x4,0x10,0x20}, {0x8,0x10,0x80}, {0x20,0x40,0x100}, {0x200,0x400,0x8000}, {0x80,0x400,0x800}, {0x800,0x1000,0x10000}, {0x100,0x1000,0x2000}, {0x2000,0x4000,0x20000} }; //存线段端点标号 int line[18][2]= { {1, 2},{1, 3},{2, 3},{2, 4},{2, 5},{3, 5}, {3, 6},{4, 5},{5, 6},{4, 7},{4, 8},{5, 8}, {5, 9},{6, 9},{6, 10},{7, 8},{8, 9},{9, 10} }; //2的幂 int exp2[18]= { 0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x100,0x200,0x400,0x800,0x1000,0x2000,0x4000,0x8000,0x10000,0x20000 }; /* 全局变量 f[] 将f()的值存下,避免重复计算 state 当前棋盘状态 MIN 初始化的极小值 */ int f[0x40000]; int state; const int MIN=-10; //计算在state这个状态下,放置某线段新得到的三角形数 int place(int state,int hash) { int already,t,get=0; for(int i=0;i<9;++i) { already=0;t=3; for(int j=0;j<3;++j) { //放置的线段是第i个三角形中的第j条 if(tri[i][j]&hash) { t=j; } //第i个三角形中的第j条已经放置 else if(tri[i][j]&state) { already++; } } //不存在于第i个三角形中 if(t==3) { continue; } //则第i个三角形是新得到的 if(already==2) { get++; } } return get; } //f() int dp(int state) { //如果当前状态已算过就直接用 if(f[state]!=MIN) { return f[state]; } int max=MIN,t; for(int i=0;i<18;++i) { //如果第i条线段没有用过 if(!(state&exp2[i])) { //放置第i条线段 t=place(state,exp2[i]); //递归计算 t+=((t)?1:-1)*dp(state|exp2[i]); //更新最大值 max=(t>max)?t:max; } } //存下当前状态的最大值,并返回 return (f[state]=max); } int main() { //freopen("in_1085.txt","r",stdin); //全局初始化 for(int i=0;i<0x40000;++i) { f[i]=MIN; } f[0x3FFFF]=0; /* b 数据块数 n 每块的局数 m 每局已经走的步数 x,y 读入的线段 t 临时变量 player 表示当前谁走(1 A,-1 B) pre 根据给出的步骤A比B多得到的三角形数 */ int b,n,m,x,y,t,player,pre; //cin>>b; //for(int i=0;i<b;++i) { cin>>n; for(int j=0;j<n;++j) { //每局初始化 pre=0; state=0; player=1; cin>>m; for(int k=0;k<m;++k) { //读入线段 cin>>x>>y; for(int l=0;l<18;++l) { //转化为hash并放置 if(line[l][0]==x&&line[l][1]==y) { t=place(state,exp2[l]); state|=exp2[l]; break; } } //新得到三角形 if(t) { pre+=(player*t); } //没有生成新三角形则换另一方走 else { player*=-1; } } //计算状态并输出,>0即A胜 cout<<"Game "<<j+1<<": "<<((pre+player*dp(state)>0)?'A':'B')<<" wins./n"; } cout<<endl; } } 本文来自CSDN博客,转载请标明出处:http://blog.csdn<a href="http://lib.csdn.net/base/dotnet" class='replace_word' title=".NET知识库" target='_blank' style='color:#df3434; font-weight:bold;'>.NET</a>/twilightgod/archive/2008/12/12/3505659.aspx
我的代码:(精简一些)
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>#include <map>using namespace std;const int MAXN = 1<<18;//三角形的hash值const int triangle[9][3] = { {1, 2, 4}, {8, 16, 128}, {4, 16, 32}, {32, 64, 1024}, {256, 512, 32768}, {128, 512, 2048}, {2048, 4096, 65536}, {1024, 4096, 8192}, {8192, 16384, 131072}};//别人的这个数组,学到了,嘿嘿嘿(1, 2, 4, 8 , 10)int tri[9][3]= { {0x1,0x2,0x4}, {0x4,0x10,0x20}, {0x8,0x10,0x80}, {0x20,0x40,0x100}, {0x200,0x400,0x8000}, {0x80,0x400,0x800}, {0x800,0x1000,0x10000}, {0x100,0x1000,0x2000}, {0x2000,0x4000,0x20000} }; //存线段端点标号 const int line[18][2] = { {1, 2}, {1, 3}, {2, 3}, {2, 4}, {2, 5}, {3, 5}, {3, 6}, {4, 5}, {4, 7}, {4, 8}, {5, 6}, {5, 8}, {5, 9}, {6, 9}, {6, 10}, {7, 8}, {8, 9}, {9, 10}};//2的幂 const int haha[18] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072};int dp[MAXN];//状态为i时,放置2的幂为ii的那条线,形成的三角形的个数;int place(int i, int ii) { int tmp = 0;//三角形个数 for(int k = 0; k < 9; k++) { int nAngle = 0; for(int t = 0; t < 3; t++) { if ((triangle[k][t]&i)) nAngle++;//第k个三角形的第t条边是否已经被放置 if (triangle[k][t]&ii) nAngle += 2;//这条边在第k个三角形里 } if (nAngle == 4)//自行体会 tmp++; } return tmp;}//用dp坐的话,肯定超时,我还不知道这样写对了没有,多求了很多东西(备忘录搜索的优势,只求了有用的状态,而且写起来简单)/*void init() { for(int i = 0; i < MAXN-64; i++) { int m = 0; for(int j = 0; i < 18; j++) if (i<<j&1) m++; if (m > 11) continue; for(int j = 0; j < 18; j++) { int ii = 1<<j; if ((ii|i) == i) continue; int tmp = place(i, ii); if (tmp) tmp += dp[i]; else tmp -= dp[i]; ii |= i; dp[ii] = max(dp[ii], tmp); } }}*///表示在state这个状态下,假设A先走,双方走法都是最优,最终A比B多得到的三角形个数void dfs(int state) {//备忘录搜索 if (dp[state] != -88) {//-88嘿嘿 return ; } for(int i = 0; i < 18; i++) if (!(haha[i]&state)) {//如果第i条线没有放, int tmp = place(state, haha[i]);//那就放 dfs(state|haha[i]);//下一状态 dp[state] = max(((tmp)?1:-1)*dp[state|haha[i]]+tmp, dp[state]);//自行体会 }}int main() { int t, m, pp = 1; for(int i = 0; i < MAXN; i++) dp[i] = -88; dp[MAXN-1] = 0;//初始化 scanf("%d", &t); while (t--) { scanf("%d", &m); int x, y, res = 0, now = 1, state = 0;//res,结果,now谁走,state当前状态 //先模拟 while (m--) { scanf("%d%d", &x, &y); int tt; for(int k = 0; k < 18; k++) if (line[k][0] == x && line[k][1] == y) { tt = place(state, haha[k]); state |= haha[k]; break; } if (!tt) now *= -1;//换人不是 = ,是 *= res += now*tt; } dfs(state); res += now*dp[state]; printf("Game %d: %c wins.\n", pp++, res>0?'A':'B'); }}
0 0
- POJ1085 The Triangle War: 记忆化搜索
- POJ1085 The Triangle War: 记忆化搜索
- poj1085 Triangle War
- poj1085 Triangle War 极大极小
- poj 1085 Triangle War (状压+记忆化搜索)
- poj 1085 (Triangle War)状压dp+记忆化搜索
- poj 1163 the triangle 记忆化搜索
- poj 1163 The Triangle (记忆化搜索)
- POJ 1163The Triangle(dp或记忆化搜索)
- POJ1163The Triangle(动态规划记忆化搜索入门精讲)
- poj 1085 Triangle War 1568 Find the Winning Move 极大极小搜索 alpha-beta剪枝
- NYOJ 18 The Triangle(dp + 记忆化)
- Poj 1085 Triangle War (极大极小搜索)
- poj 1085 Triangle War 极大极小搜索
- Treats for the Cows 记忆化搜索
- Count the string(记忆化搜索)
- POJ1085
- POJ 1085 Triangle War(博弈,極大極小搜索+alpha_beta剪枝)
- 扫雷游戏C语言模拟实现
- android dialog
- 正则表达式匹配两个特殊字符中间的内容
- SICP 1.38
- 堆栈的深入个人理解
- POJ1085 The Triangle War: 记忆化搜索
- 自定义横向带刻度progressbar
- 常用的jar包(三)
- tensorflow 几个android demo源码环境搭建
- swoole+websocket+html5实现的简易版直播功能
- android studio使用Aidl跨进程调用服务
- Python Selenium实现自动登录163邮箱
- nginx构建static location tree和查找
- 程序执行时间