您的位置:首页 > 其它

poj 1085 Triangle War

2016-02-29 11:02 316 查看
人生第一道真正意义上的极大极小过程+alphabeta剪枝。

其实一开始让我写alphabeta剪枝我是拒绝的,于是我写了个记忆化搜索,TLE了。。。。。。。

哦然后优化了一下,300多MS A了

但是不爽啊

说好的博弈论呢

当然要用正解了

于是学了下alphabeta剪枝,其实挺简单的,就是alpha为已知max游戏者的下界,beta为min游戏者的上界,如果beta<=alpha就剪掉。

假设在博弈树上当前节点为MAX节点,有一个alpha值a,父节点为MIN节点,有一个beta值b,如果b<=a,那么MIN节点绝对不会选择走MAX节点,更不会走它的任意子树了,于是把MAX节点的其它子树剪掉。

如果当前节点为MIN节点,同理

记忆化搜索:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1<<20;
const int inf=-10;
int tag[9][3]={{1,2,3},{4,5,8},{3,5,6},{6,7,9},{10,11,16},{8,11,12},{12,13,17},{9,13,14},{14,15,18}};
int l[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}};
int count
,f
;
int bin[30];
void print(int s){
for(int i=0;i<19;i++,s>>=1)printf("%d",s&1);
putchar('\n');
}
void build(){
bin[1]=1;
for(int i=2;i<=19;i++)bin[i]=bin[i-1]<<1;
}
int calc(int s,int h){
int a,b,c=0;
for(int i=0;i<9;i++){
a=0;b=3;
for(int j=0;j<3;j++)
if(bin[tag[i][j]]&h)b=j;
else if(bin[tag[i][j]]&s)a++;
if(b==3)continue;
if(a==2)c++;
}
return c;
}
int dp(int s){
if(f[s]!=inf)return f[s];
if(s==bin[19]-1)return f[s]=0;
int mx=inf;
for(int i=1;i<=18;i++){
if(s&bin[i])continue;
int t=s|bin[i],ans=calc(s,bin[i]);
ans+=(ans?1:-1)*dp(t);
mx=max(mx,ans);
}
return f[s]=mx;
}
int main(){
int cas;scanf("%d",&cas);
build();
for(int i=0;i<N;i++)f[i]=inf;
for(int kase=1;kase<=cas;kase++){
int m;scanf("%d",&m);
int s=0,player=1,pre=0,x,y;
while(m--){
scanf("%d%d",&x,&y);if(x>y)swap(x,y);
for(int i=0;i<18;i++)
if(l[i][0]==x&&l[i][1]==y){
int t=s|bin[i+1],cnt=calc(s,bin[i+1]);
if(cnt)pre+=player*(cnt);
else player*=-1;
s=t;
break;
}
}
printf("Game %d: ",kase);
int ans=pre+player*dp(s);
if(ans>0)putchar('A');else putchar('B');
puts(" wins.");
}
return 0;
}


alphabeta剪枝
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int mat[11][11]={
{0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,2,3,4,0,0,0,0,0},
{0,1,2,0,0,5,6,0,0,0,0},
{0,0,3,0,0,7,0,9,10,0,0},
{0,0,4,5,7,0,8,0,11,12,0},
{0,0,0,6,0,8,0,0,0,13,14},
{0,0,0,0,9,0,0,0,15,0,0},
{0,0,0,0,10,11,0,15,0,16,0},
{0,0,0,0,0,12,13,0,16,0,17},
{0,0,0,0,0,0,14,0,0,17,0}
};
int tri[9]={7,152,52,352,34304,3200,71680,12544,155648};
int bin[30],all;
void print(int s){
for(int i=0;i<19;i++,s>>=1)printf("%d",s&1);
putchar('\n');
}
void build(){
bin[1]=1;
for(int i=2;i<=19;i++)bin[i]=bin[i-1]<<1;
all=bin[19]-1;
}
int calc(int s,int t){
int cnt=0;
for(int i=0;i<9;i++)
if((s&tri[i])!=tri[i]&&(t&tri[i])==tri[i])cnt++;
return cnt;
}
int alphabeta(int s,int player,int alpha,int beta,int ca,int cb){
if(ca>=5)return 1;
if(cb>=5)return -1;
if(s==all)ca>cb?1:-1;
int remain=(~s)&all;
while(remain){
int now=remain&(-remain);
int tmp=calc(s,s|now);
int ta=ca,tb=cb;
player?tb+=tmp:ta+=tmp;
int v;
if(tmp)v=alphabeta(s|now,player,alpha,beta,ta,tb);
else v=alphabeta(s|now,player^1,alpha,beta,ta,tb);
player?beta=min(beta,v):alpha=max(alpha,v);
if(beta<=alpha)break;
remain-=now;
}
return player?beta:alpha;
}
int main(){
int cas;scanf("%d",&cas);
build();
for(int kase=1;kase<=cas;kase++){
int m;scanf("%d",&m);
int s=0,player=0,x,y,ca=0,cb=0;
while(m--){
scanf("%d%d",&x,&y);
int t=s|bin[mat[x][y]+1];
int cnt=calc(s,t);
player?cb+=cnt:ca+=cnt;
if(!cnt)player^=1;
s=t;
}
printf("Game %d: ",kase);
int ans=alphabeta(s,player,-1,1,ca,cb);
if(ans>0)putchar('A');else putchar('B');
puts(" wins.");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: