【α-β剪枝】——poj1085——三角战争(附资料)

《对弈程序基本技术》专题 最小-最大搜索:http://www.xqbase.com/computer/search_minimax.htm
《对弈程序基本技术》专题 Alpha-Beta搜索 :http://www.xqbase.com/computer/search_alphabeta.htm
Wikipedia MinMax :http://en.wikipedia.org/wiki/Minimax
Wiki Alpha–beta pruning :http://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning
Minmax Explained:http://ai-depot.com/articles/minimax-explained/1/
讲解极小极大 (Minimax Explained) [译] :http://www.starming.com/index.php?action=plugin&v=wave&tpl=union&ac=viewgrouppost&gid=34694&tid=15725
最小最大原理与搜索方法:http://blog.pfan.cn/rickone/16930.html

 

                                           Triangle War

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3361   Accepted: 1310

Description

Triangle War is a two-player game played on the following triangular grid: 

Two players, A and B, take turns filling in any dotted line connecting two dots, with A starting first. Once a line is filled, it cannot be filled again. If the line filled by a player completes one or more triangles, she owns the completed triangles and she is awarded another turn (i.e. the opponent skips a turn). The game ends after all dotted lines are filled in, and the player with the most triangles wins the game. The difference in the number of triangles owned by the two players is not important. 

For example, if A fills in the line between 2 and 5 in the partial game on the left below: 

Then, she owns the triangle labelled A and takes another turn to fill in the line between 3 and 5. B can now own 3 triangles (if he wishes) by filling in the line between 2 and 3, then the one between 5 and 6, and finally the one between 6 and 9. B would then make one more move before it is A's turn again. 
In this problem, you are given a number of moves that have already been made. From the partial game, you should determine which player will win assuming that each player plays a perfect game from that point on. That is, assume that each player always chooses the play that leads to the best possible outcome for himself/herself.

Input

You will be given a number of games in the input. The first line of input is a positive integer indicating the number of games to follow. Each game starts with an integer 6 <= m <= 18 indicating the number of moves that have been made in the game. The next m lines indicate the moves made by the two players in order, each of the form i j (with i < j) indicating that the line between i and j is filled in that move. You may assume that all given moves are legal.

Output

For each game, print the game number and the result on one line as shown below. If A wins, print the sentence "A wins." If B wins, print "B wins."

Sample Input

4 
6 
2 4 
4 5 
5 9 
3 6 
2 5 
3 5 
7 
2 4 
4 5 
5 9 
3 6 
2 5 
3 5 
7 8 
6 
1 2 
2 3 
1 3 
2 4 
2 5 
4 5 
10 
1 2 
2 5 
3 6 
5 8 
4 7 
6 10 
2 4 
4 5 
4 8 
7 8 

Sample Output

Game 1: B wins.

Game 2: A wins.

Game 3: A wins.

Game 4: B wins.


题意:

AB轮流在包含9个小三角形的大三角形中放边,当某人放上一条边后构成一个小三角形,则这个人得一分,谁得的分多谁就赢了。

 

思路:

maxmin搜索 + alpha-beta剪枝,过程是对这个大三角形就行压缩,共17条边。

然后搜索。这个题里,alpha为1,表示A可以赢,出现搜索值返回的是1的时候其他的就不用再搜了。

beta值为-1,表示B可以赢,同理进行剪枝。

 

代码如下:

#include<cstdio>
using namespace std;

//10个顶点之间的连线编号
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}
};

//9个三角形组成的边状态压缩一下
int tri[9]={7,152,52,352,34304,3200,71680,12544,155648};
int STATUS=(1<<18)-1;

int Get_Status(int old,int seg,int &cnt)
{
    int now=old|seg;
    for(int i=0;i<9;i++){
        //之前不包含这个三角形,现在包含了
        if((old&tri[i])!=tri[i]&&(now&tri[i])==tri[i])
            cnt++;
    }
    return now;
}

int MaxSearch(int state,int alpha,int ca,int cb);
int MinSearch(int state,int beta,int ca,int cb)
{
    //出现5个三角形,胜负已分
    if(ca>=5) return 1;
    if(cb>=5) return -1;
    //所有的边都取了,游戏也结束
    if(state==STATUS) return ca>cb?1:-1;
    int ans=1;
    int remain=(~state)&STATUS;  //剩下还有哪些边可以取
    while(remain)
    {
        int seg=remain&(-remain); //枚举
        int ta=ca,tb=cb;
        int now=Get_Status(state,seg,tb),tmp;
        //是否有新的三角形生成
        if(tb>cb) tmp=MinSearch(now,beta,ca,tb);
        else tmp=MaxSearch(now,ans,ca,tb);
        if(tmp<ans) ans=tmp;
        //beta剪枝
        if(tmp<=beta) return ans;
        remain-=seg;
    }
    return ans;
}

int MaxSearch(int state,int alpha,int ca,int cb){
    //出现5个三角形,胜负已分
    if(ca>=5) return 1;
    if(cb>=5) return -1;
    //所有的边都取了,游戏也结束
    if(state==STATUS) return ca>cb?1:-1;
    int ans=-1;
    int remain=(~state)&STATUS;  //剩下还有哪些边可以取
    while(remain)
    {
        int seg=remain&(-remain); //枚举
        int ta=ca,tb=cb;
        int now=Get_Status(state,seg,ta),tmp;
        //是否有新的三角形生成
        if(ta>ca) tmp=MaxSearch(now,alpha,ta,cb);
        else tmp=MinSearch(now,ans,ta,cb);
        if(tmp>ans) ans=tmp;
        //alpha剪枝
        if(tmp>=alpha) return ans;
        remain-=seg;
    }
    return ans;
}

int main()
{
    int t,cas=0;
    scanf("%d",&t);
    while(t--)
    {
        int n,u,v;
        scanf("%d",&n);
        //已经走了多少步,当前边的状态
        int cnt=0,state=0;
        //两个人分别有几个三角形
        int ca=0,cb=0;
        while(n--)
        {
            scanf("%d%d",&u,&v);
            int ta=ca,tb=cb;
            state=Get_Status(state,1<<mat[u][v],(cnt&1)?cb:ca);
            //没有新的三角形,
            if(ta==ca&&tb==cb)
                cnt++;
        }
        int ans;
        if(cnt&1) 
            ans=MinSearch(state,-1,ca,cb);
        else 
            ans=MaxSearch(state,1,ca,cb);
        
        printf("Game %d: %c wins.\n",++cas,ans==1?'A':'B');
    }
    return 0;
}

 

posted @ 2016-07-23 09:31  琥珀川||雨露晨曦  阅读(335)  评论(0)    收藏  举报