射击游戏

射击游戏

时间: 1ms        内存:128M

描述:

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

 

游戏规则如下:

1、   AB轮流射击,A先射击。

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

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

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

 

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

 

行编号(从下往上数)

子弹前进方向

威力(随机值)

刚射击后

积木稳定后

2

从右往左

1

(同左图)

1

从右往左

2

1

从左往右

3

 

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

 

输入

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

 

输出

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

输入:

输出:

示例输入:

3
2 1 1
0

示例输出:

0.555556

提示:

参考答案(内存最优[1836]):

#include <cstdio>
#include <algorithm>
using namespace std;

#define X(A,B) (A[B[0]][B[1]][B[2]][B[3]][B[4]][B[5]])

double cache[7][7][7][7][7][7];
bool vis[7][7][7][7][7][7];

double win(int h[6])
{
  if (X(vis, h)) return X(cache, h);
  X(vis, h)=true;
  X(cache, h)=0.;

  int mx=0;
  for (int i=0; i < 6; i++) mx=max(mx, h[i]);

  int i=0, hh[6];
  for (int j=0; j < mx; j++){
    for (int d=0; d < 2; d++){
      i=0 + 5 * d;
      double loss=0.;
      for (int p=1; p <= 3; p++){
        for (int k=0; k < 6; k++) hh[k]=h[k];
        int pp=p;
        int k=i;
        while (pp){
          if (k < 0 || k > 5) break;
          if (hh[k] > j) hh[k]--, pp--;
          k+=1 - 2 * d;
        }
        loss+=win(hh);
      }
      loss=(1 - loss / 3.);
      if (loss > X(cache, h)) X(cache, h)=loss;
    }
  }
  return X(cache, h);
}

int main() {
  int n;
  while (scanf("%d", &n) == 1 && n) {
    int h[6]={0};
    for (int i=0; i < n; i++) scanf("%d", &h[i]);
    printf("%.6lf\n", win(h));
  }
  return 0;
}

参考答案(时间最优[36]):

#include<iostream>
#include<cstdio>
using namespace std;
#define X(A,B) (A[B[0]][B[1]][B[2]][B[3]][B[4]][B[5]])
double cache[7][7][7][7][7][7];//概率
bool vis[7][7][7][7][7][7];//统计
double win(int h[6])
{
    if(X(vis,h))
    return X(cache,h);
    X(vis,h)=true;
    X(cache,h)=0.0;
    int  mx=0;
    for(int i=0;i<6;i++)
        mx=max(mx,h[i]);//mx为最高列
    int i=0,hh[6];
    for(int j=0;j<mx;j++)
    {
        for(int d=0;d<2;d++)
        {
            i=5*d;
            double loss=0;
            for(int p=1;p<=3;p++)
            {
                for(int k=0;k<6;k++)
                    hh[k]=h[k];
                int pp=p;
                int k=i;
                while(pp)
                {
                if(k<0||k>5)
                    break;
                if(hh[k]>j)
                hh[k]--,pp--;
                k+=1-2*d;
                }
                loss+=win(hh);
            }
        loss=(1-loss/3.0);
        if(loss>X(cache,h))
        X(cache,h)=loss;
      }
  }
  return X(cache,h);
}
int main()
{ int n;
  while(scanf("%d",&n)==1&&n)
  {
    int h[6]={0};
    for(int i=0;i<n;i++)
        scanf("%d",&h[i]);
    printf("%.6lf\n",win(h));
  }
  return 0;
}

题目和答案均来自于互联网,仅供参考,如有问题请联系管理员修改或删除。

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注