POJ1085

题意:

        游戏有A、B两人参与。A先走,每人每次任选一条虚线填成实线。而如果某人填完一条线段后,该线段与另外两条相邻的实线组成了一个单位三角形,该三角形被标记为该游戏者所有,且该游戏者必须接着再填一条虚线。当18条线段被填充完毕后,拥有三角形多的玩家获胜。

        首先输入一个数 T ,表示试验次数;接着一个数 n,表示当前局面已经走了 n 条边;接着输入 n 对数,每对数字表示一条填充边,由 A 开始。问从给出的局面开始,双方都采取最优策略,最终谁会取胜。

【实验原理】

 1 最单纯的极大极小算法

 

        局面估价函数:我们给每个局面(state)规定一个估价函数值 f,评价它对于己方的有利程度。胜利的局面的估价函数值为 +oo,而失败的局面的估价函数值为–oo。

 

        Max 局面:假设这个局面轮到己方走,有多种决策可以选择,其中每种决策都导致一种子局面(sub-state)。由于决策权在我们手中,当然是选择估价函数值 f 最大的子局面,因此该局面的估价函数值等于子局面 f 值的最大值,把这样的局面称为 max 局面。

 

        Min 局面:假设这个局面轮到对方走,它也有多种决策可以选择,其中每种决策都导致一种子局面(sub-state)。但由于决策权在对方手中,在最坏的情况下,对方当然是选择估价函数值 f 最小的子局面,因此该局面的估价函数值等于子局面 f 值的最小值,把这样的局面称为 max 局面。

 

        终结局面:胜负已分(假设没有和局).

2.alpha-beta剪枝

简单地说就是用两个参数 alpha 和 beta 表示当前局面的父局面的估价函数值 f()。如果当前局面为 min 局面,则需要借助父局面目前已求得的 f() (即 alpha)来判断是否需要继续搜索下去;如果当前局面为 max 局面,则需要借助父局面目前已求得的 f() (即 beta)。

 

思路:

  显然是博弈问题,也是 alpha-beta 搜索算法的基础应用。一个比较关键的问题是局面的存储。整个棋盘有18条边,因此可以用一个整型来存储一个局面


如果每条边用红色数字表示(当然也可以不这样排列),则用 2^0 = 1 表示 edge(1, 2) 或 edge(2, 1),用 2^1 = 2(即二进制10)表示edge(2, 3) 或 edge(3, 2),用2^2 =4(即二进制100)表示 edge(1, 3) 或 edge(3, 1) ...

【实验环境】

 VS2012

【实验方案设计】

1.    minimax算法

2.    alpha-beta剪枝

 

【源程序】

1.  minimax算法

  #include<iostream>

#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 STATUS = (1 << 18) - 1;

int bestmax=1<<20;

int bestmin=-1<<20;

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 minimax(int player,int state,int ca,int cb)

{

    if (ca >= 5)

       return 1;

    if (cb >= 5)

       return -1;

 

    if (state == STATUS)

       return ca > cb ? 1 : -1;

    int remain = (~state) & STATUS;

    if(player==1)

    {

       int ans=-1;

       while(remain)

       {

           int seg = remain & (-remain);

           int ta = ca, tb = cb;

           int now = Get_Status(state, seg, ta), tmp;

           if(ta>ca)

              tmp=minimax(player,now,ta,cb);

           else

              tmp=minimax(player^1,now,ta,cb);

           if(tmp>ans)

              ans=tmp;

           remain-=seg;

       }

       return ans;

    }

    else{

       int ans=1;

       while(remain)

       {

           int seg = remain & (-remain);

           int ta = ca, tb = cb;

           int now = Get_Status(state, seg, tb), tmp;

           if(tb>cb)

              tmp=minimax(player,now,ca,tb);

           else

              tmp=minimax(player^1,now,ca,tb);

           if(tmp<ans)

              ans=tmp;

           remain-=seg;

       }

       return ans;

    }

}

int main()

{

    int t, cas = 0;

    cin>>t;

    while (t--)

    {

       int n, u, v;

       cin>>n;

   

       int cnt = 0, state = 0;

   

       int ca = 0, cb = 0;

       while (n--)

       {

           cin>>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=minimax(0,state,ca,cb);

       else

       ans=minimax(1,state,ca,cb);

       char ch=(ans==1)?'A':'B';

      cout<<"Game "<<++cas<<": "<<ch<<" wins."<<endl;

    }

    return 0;

}

2.  alpha-beta算法

  #include <iostream>

#include <cstdio>

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 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)

{

 

    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;

      

       if (tmp <= beta)

           return ans;

       remain -= seg;

    }

    return ans;

}

 

int MaxSearch(int state, int alpha, int ca, int cb)

{

   

    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;

   

       if (tmp >= alpha)

           return ans;

       remain -= seg;

    }

    return ans;

}

 

int main()

{

    int t, cas = 0;

    cin>>t;

    while (t--)

    {

       int n, u, v;

       cin>>n;

   

       int cnt = 0, state = 0;

   

       int ca = 0, cb = 0;

       while (n--)

       {

           cin>>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);

           char ch=(ans==1)?'A':'B';

      cout<<"Game "<<++cas<<": "<<ch<<" wins."<<endl;

    }

    return 0;

}

【实验结果及结论】

结果:

1.    minimax算法未剪枝时,能得出结果,但是耗时太大,特别是该检验数据都是5层以上。Oj平台测试如下,显示时间超出(TLE)

2.    加入alpha-beta剪枝后

耗时454ms,这也是poj的边界数据结果。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值