POJ - 1085 Triangle War 极小极大搜索+alpha-beta剪枝

题目:有一个这样的图形


一共10个顶点,有A,B两个玩家,A先手,每次每个玩家可以选择连接2个相邻但是没连接的顶点,构成的三角形属于当前操作者,并且可以额外再操作一次,谁拥有的三角形数目多谁胜。给出前面的一些操作,问你是A胜还是B胜

思路:极小极大搜索+alpha-beta剪枝

给两个相邻顶点的边编个号,一共有18条边分别编号为0~17,9个三角形,可以用三角形的三条边的二进制和表示

代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f

//对10个顶点之间的边的编号0~17
int idx[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}
};
//用三角形的3各顶点的二进制和代表每个三角形
int tri[9]={7,152,52,352,34304,3200,71680,12544,155648};
int End=(1<<18)-1;
int get_status(int old,int seg,int &num){
    int now=old|seg;
    for(int i=0;i<9;i++)
        if((old&tri[i])!=tri[i]&&(now&tri[i])==tri[i])
            num++;
    return now;
}
int MaxSearch(int state,int alpha,int ca,int cb);
int MinSearch(int state,int beta,int ca,int cb);
int MinSearch(int state,int beta,int ca,int cb){
    if(ca>=5) return 1;//A赢了
    if(cb>=5) return -1;//B赢了
    if(state==End) return ca>cb?1:-1;
    int remain=(~state)&End;
    int ans=1;
    while(remain){
        int seg=remain&(-remain);
        int ta=ca,tb=cb;
        int now=get_status(state,seg,tb);
        int tmp;
        if(tb>cb) tmp=MinSearch(now,beta,ta,tb);//形成一个三角形可以多一个回合
        else tmp=MaxSearch(now,ans,ta,tb);
        if(ans>tmp) ans=tmp;
        if(ans<=beta) return ans;
        remain-=seg;
    }
    return ans;
}
int MaxSearch(int state,int alpha,int ca,int cb){
    if(ca>=5) return 1;//A赢了
    if(cb>=5) return -1;//B赢了
    if(state==End) return ca>cb?1:-1;
    int remain=(~state)&End;
    int ans=-1;
    while(remain){
        int seg=remain&(-remain);
        int ta=ca,tb=cb;
        int now=get_status(state,seg,ta);
        int tmp;
        if(ta>ca) tmp=MaxSearch(now,alpha,ta,tb);
        else tmp=MinSearch(now,ans,ta,tb);
        if(ans<tmp) ans=tmp;
        if(ans>=alpha) return ans;
        remain-=seg;
    }
    return ans;
}
int main(){

//    freopen("D:\\input.txt","r",stdin);
//    freopen("D:\\output.txt","w",stdout);
    int T,cas=0,n,a,b;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int staus=0,ca=0,cb=0,pos=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&a,&b);
            int ta=ca,tb=cb;
            if(pos%2==0)
                staus=get_status(staus,(1<<idx[a][b]),ca);
            else
                staus=get_status(staus,(1<<idx[a][b]),cb);
            if(ta==ca&&tb==cb)
                pos++;
        }
        int ans;
        if(pos%2==0) ans=MaxSearch(staus,1,ca,cb);
        else ans=MinSearch(staus,-1,ca,cb);
        if(ans==1)
            printf("Game %d: A wins.\n",++cas);
        else
            printf("Game %d: B wins.\n",++cas);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值