poj 3317 Stake Your Claim(极大极小搜索+记忆化搜索+状态压缩)
来源:互联网 发布:淘宝商家联盟 编辑:程序博客网 时间:2024/06/06 12:22
题意:给定一个n*n的矩阵(n<=8),两个人依次向矩阵里放0和1,玩家的得分为自己牌的数量减去对方牌的数量。
问先手的下一步最佳得分位置和得分。
设先手放0. c0为0的数量,c1为1的数量。
那么先手得分为c0 - c1;
后手得分为c1-c0;
假设估价函数为g(x)=c0(x)-c1(x).x为某一状态。
可以看出,先手求当前所有选择中g(x)的最大值,后手求当前所有选择中的最小值。
这就是博弈中的极大极小搜索了。
直接爆搜的话会有许多的重复状态。(每次只是换了个地方放0或1,很容易重复)
由于空位小于等于10。考虑用三进制压缩状态。
0表示当前位空,1表示放0, 2表示放1.
剪枝的话,可以用alpha-beta剪枝,不过此题没什么效果。
#include<cstdio>#include<cstring>#define MAX(a,b) a>b?a:busing namespace std;const int INF=(1<<30);char map[12][12];int empty[12];int full[12];//空位int cnt;int n;bool vis[12][12]={false};int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};int c3[12];//c3[i]记录 3^i//估价函数为g(x)=c0(x)-c1(x);状态x的情况下 0的个数-1的个数struct Point{ int x,y; int score; Point(){} Point(int a,int b,int c){x=a;y=b;score=c;}}dp[60000];bool cmp(struct Point Z,int i){int xx=empty[i]/n,yy=empty[i]%n;if(xx!=Z.x)return xx<Z.x;return yy<Z.y;}void init(){ cnt=0;}bool check(int x,int y){ if(x<0||x>=n||y<0||y>=n)return 0; return 1;}int xx=0;void dfs(int x,int y,int c){ vis[x][y]=1; xx++; for(int i=0;i<4;i++){ int x1=x+dx[i],y1=y+dy[i]; if(check(x1,y1)&&!vis[x1][y1]&&map[x1][y1]==c+'0'){ dfs(x1,y1,c); } }}int getsum(){ memset(vis,0,sizeof(vis)); int c0=0,c1=0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(!vis[i][j]){ xx=0; if(map[i][j]=='0')dfs(i,j,0),c0=MAX(c0,xx); else if(map[i][j]=='1') dfs(i,j,1),c1=MAX(c1,xx); } } } return c0-c1;//估价函数}struct Point MaxSearch(int state,int now,int pos);struct Point MinSearch(int state,int now,int pos);struct Point MaxSearch(int state,int now,int pos){//state为当前棋盘是否填充的二进制状态。now为填充棋盘的三进制状态 struct Point Z,Y;if(state==0){Z.score=getsum();Z.x=empty[pos]%n;Z.y=empty[pos]/n;return Z;}if(dp[now].score!=-INF)return dp[now];int st=state;Z.score=-INF;//ans为本层最优值。while(st){int k=st&(-st),cur;//k为最右边的1,即从右往左依次选择空棋盘位置。for(cur=0;cur<cnt;cur++){if((1<<cur)&k)break;}map[empty[cur]/n][empty[cur]%n]='0';Y=MinSearch(state^k,now+c3[cur],cur);map[empty[cur]/n][empty[cur]%n]='.';if(Z.score<Y.score||(Z.score==Y.score&&cmp(Z,cur)))Z.score=Y.score,Z.x=empty[cur]/n,Z.y=empty[cur]%n;st-=k;}return dp[now]=Z;}struct Point MinSearch(int state,int now,int pos){struct Point Z,Y;if(state==0){Z.score=getsum();Z.x=empty[pos]%n;Z.y=empty[pos]/n;return Z;}if(dp[now].score!=-INF)return dp[now];int st=state;Z.score=INF;//ans为本层最优值。while(st){int k=st&(-st),cur;//k为最右边的1,即从右往左依次选择空棋盘位置。for(cur=0;cur<cnt;cur++){if((1<<cur)&k)break;//cur为从右数的空位标号。}map[empty[cur]/n][empty[cur]%n]='1';Y=MaxSearch(state-k,now+2*c3[cur],cur);map[empty[cur]/n][empty[cur]%n]='.';if(Z.score>Y.score||(Z.score==Y.score&&cmp(Z,cur)))Z.score=Y.score,Z.x=empty[cur]/n,Z.y=empty[cur]%n;st-=k;}return dp[now]=Z;}void input(){int cnt0,cnt1;cnt0=cnt1=0; for(int i=0;i<n;i++){ scanf("%s",map[i]); for(int j=0;j<n;j++) { if(map[i][j]=='1')cnt1++; if(map[i][j]=='0')cnt0++; if(map[i][j]=='.')empty[cnt++]=i*n+j; } }if(cnt0>cnt1){//都改成0为先手for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(map[i][j]=='0')map[i][j]='1';else if(map[i][j]=='1')map[i][j]='0';}}}for(int i=0;i<c3[cnt];i++)dp[i].score=-INF;}int main(){c3[0]=1;for(int i=1;i<=10;i++)c3[i]=c3[i-1]*3; while(scanf("%d",&n)!=EOF&&n){ init(); input(); Point ans=MaxSearch((1<<cnt)-1,0,0); printf("(%d,%d) %d\n",ans.x,ans.y,ans.score); } return 0;}
0 0
- poj 3317 Stake Your Claim(极大极小搜索+记忆化搜索+状态压缩)
- poj 3317 Stake Your Claim(极大极小搜索经典 a-b+剪枝+记忆化dp)
- POJ 3317 Stake Your Claim(极大极小搜索+alpha-beta剪枝)
- pku3317 Stake Your Claim 极大极小搜索+状压+AB剪枝
- poj3317 Stake Your Claim极大极小
- POJ 3317 博弈-极大极小过程+记忆化搜索+剪枝
- POJ 3317 Stake Your Claim
- Poj 1085 Triangle War (极大极小搜索)
- POJ 4049 Chess 极大极小搜索 -
- poj 1085 Triangle War 极大极小搜索
- poj1568 极大极小搜索
- [算法] 极大极小搜索
- 极大极小搜索算法
- 极大极小搜索
- 极大极小搜索
- 极大极小搜索问题
- 极大极小搜索
- 极大极小搜索
- 第14题
- 纯CSS写弹出层样式
- [c++]选择排序
- 整数划分问题——动态规划
- c语言之统计元音
- poj 3317 Stake Your Claim(极大极小搜索+记忆化搜索+状态压缩)
- void Oxygen::ComboBoxData::setButton(GtkWidget*): Assertion `!_button._widget' failed.
- 关于加班效率的思考
- UILabel 详解
- [c++]快速排序
- dfdgdg gdg
- 反汇编学习之路之查找参考字符串
- Java多线程面试题归纳
- Eclipse 快捷键