第六届湖南省省赛 射击游戏(概率博弈,dfs)

射击游戏

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 10   Solved: 6
[ Submit][ Status][ Web Board]

Description

A和B在玩一个射击游戏,战场由若干单位正方形积木组成。积木占据了连续的若干列,且图形周长等于它最小包围矩形的周长。下图(a)是一个合法的战场,但(b)和(c)都不是:(b)中有空列;(c)的图形周长为14,而最小包围矩形(用虚线画出)的周长为12。受重力影响,每个积木的正下方要么是地面,要么是另一个积木。为了让战场看上去错落有致、玩着更刺激,它不能恰好是一个矩形(即:不能每列积木都一样高)。

 

游戏规则如下:

1、   A和B轮流射击,A先射击。

2、   每次射击时,首先选择一行(该行必须至少有一个积木),以及“左”和“右”中的一个方向,然后往这个方向开火。子弹的威力为1~3的均匀随机整数(即:威力为1、2、3的概率各为1/3),表示子弹能打掉的积木个数,被打掉的积木将直接从战场中消失。如果该行的积木个数小于威力值,则子弹将在打掉该行所有积木后消失。例如,若选择往右射击从下往上数第3行,且威力为2,且这一行一共有4个积木,则最左边的两个积木将被打掉。注意:这两个积木可以不连续。

3、   每次射击完成后,悬空的积木垂直往下落。所有积木不再下落后,下一位选手才能开始射击。

4、   谁打掉了最后一个积木,谁就获胜。

 

假定开局是,根据规则1,A先开火。射击后,B可能面临的后续局面中的其中三个如下表:

 

行编号(从下往上数)

子弹前进方向

威力(随机值)

刚射击后

积木稳定后

2

从右往左

1

(同左图)

1

从右往左

2

1

从左往右

3

 

假定A和B都足够聪明,采取让自己获胜概率尽量高的策略,你的任务是计算出A获胜的概率。

 

输入

输入文件最多包含25组测试数据,每个数据仅包含两行,第一行是整数n(1<=n<=6),即积木的列数。第二行包含n个正整数h1, h2,..., hn(1<=hi<=6),表示从左往右数第i列的高度。积木的排列方式保证符合题目描述(即:图形周长等于它最小包围矩形的周长,且各列的高度不全相同)。n=0表示输入结束,你的程序不应当处理这一行。

 

输出

对于每组数据,输出仅一行,即A获胜的概率,四舍五入保留六位小数。

Input

Output

Sample Input

32 1 10

Sample Output

0.555556
思路:一开始不理解 假定A和B都足够聪明,采取让自己获胜概率尽量高的策略,你的任务是计算出A获胜的概率。

其实就是说在任意一种方式下都是取得胜利的最大概率,所以要从所有可能的情况(1~6行,从左or从右)里取一个最大的

那么直接去dfs枚举即可,注意这里涉及到了一点博弈的知识。

当状态为全0的时候是必败态,在这个状态下获胜概率为0

当前状态所能到达的下一个状态的最大获胜概率是当前状态对应的这个人的最小获胜概率,所以累加起来然后用1减掉即是我们要求的当前状态的最大获胜概率(可以理解为AB两个人一轮一轮的射击,我们现在要算A这个人最大获胜概率,那么必然等于1-下一个状态(此时为B)最大获胜概率)

代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n;
double dp[7][7][7][7][7][7];
double dfs(int *h)///从第一列到最后一列分别有多少个积木
{
    if(dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]]!=-1) return dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]];
    dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]]=0.0;
    for(int i=1; i<=6; i++) ///往第i行开枪
    {
        double ans=0;
        int num=0;
        for(int j=0; j<6; j++) ///枚举列
            if(h[j]>=i)
                num++;
        if(!num) break;
        for(int j=1; j<=3; j++)
        {
            int hh[6];
            for(int k=0;k<6;k++) hh[k]=h[k];
            num=0;
            for(int k=0; k=i)
                {
                    num++;
                    hh[k]--;
                }
                if(num==j) break;
            }
            ans+=1-dfs(hh);
        }
        dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]]=max(dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]],ans/3.0);
        ans=0;
        for(int j=1; j<=3; j++)
        {
            int hh[6];
            for(int k=0;k<6;k++) hh[k]=h[k];
            num=0;
            for(int k=5; k>=0; k--)
            {
                if(h[k]>=i)
                {
                    num++;
                    hh[k]--;
                }
                if(num==j) break;
            }
            ans+=1-dfs(hh);
        }
        dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]]=max(dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]],ans/3.0);
    }
    return dp[h[0]][h[1]][h[2]][h[3]][h[4]][h[5]];
}
int main()
{
    int h[6];
    while(~scanf("%d",&n)&&n)
    {
        memset(h,0,sizeof(h));
        for(int i=0; i




你可能感兴趣的:(搜索)