打气球 数学期望

NKOJ 4249 打气球

问题描述

周末何老板到磁器口游玩。街边有小贩在组织一种打气球游戏,何老板很感兴趣。
店家立了一块布,布上画了N*N的方格,有的方格里挂上了气球,有的没有。
游戏规则如下:

第1步.观察。如果每一行都至少有一个方格没有气球,同时每一列都至少有一个方格没有气球,游戏结束。否则进行第2步。
第2步.抛骰子。店家拿出一个特制的骰子,该骰子有N个面,上面依次有1到N这N个数字。玩家先后抛两次骰子,设第一次抛出的数字为x,设第二次抛出的为y (注:抛出的数字是随机的)。
第3步.打气球。若坐标为(x,y)的格子里有气球,玩家必须将其打爆。子弹1块钱一发。如果该格子没有气球,忽略该格子,玩家不用开枪,但玩家也需要支付给店家1块钱。
第4步.继续。执行第1步。

何老板是个神枪手,他能做到百发百中。他想你帮他算算,对于当前给出的这局游戏,预计要花多少钱才能结束。

输入格式

第一行,两个整数n和m,n表示方格的尺寸,m表示游戏开始时,有m个格子里是没有气球的。
接下来m行,每行两个整数x,y,表示坐标为x,y的格子里没有气球。

输出格式

一行,一个实数,完成游戏预计花费,保留2个小数位。

样例输入 1

5 2
2 3
4 1

样例输出 1

11.77

样例输入 2

2 2
1 1
1 2

样例输出 2

2.00

样例输入 3

1 1
1 1

样例输出 3

0.00

数据范围

1 ≤ n ≤ 2000
0 ≤ m ≤ min(n^2, 20000)
1≤x,y≤n


显然是数学期望。但是由于没定出状态导致考试时爆零了。其实现在看来状态也比较显然。

为了求数学期望,我们要想办法表示一些状态,并推导出状态的转移。这道题使用整个方格作为状态显然是不现实的。考虑应当使用怎样的状态。

既然题目中的终止状态是每行每列都至少有一个空位,那么不妨考虑状态 f[i][j] 表示有i行没有空位,j列没有空位时的数学期望。那么终止状态就是 f[0][0] 。考虑 f[i][j] 的递推方程。

这里写图片描述

图中红黄蓝三种颜色表示还有气球。注意到每次选到的坐标实际上有四种情形:

(1)不会造成状态转移(白)
(2)会使满行的数目减少一(黄)
(3)会使满列的数目减少一(绿)
(4)同时使满行、满列的数目减少一(红)

那么容易计算出坐标为每种情况的概率,这样就可以得到下面的式子:

f[i][j]=N2[(i+j)Nij]N2f[i][j]+jNijN2f[i][j1]+iNijN2f[i1][j]+ijN2f[i][j]+1

移项后整理得:

f[i][j]=(jNij)f[i][j1]+(iNij)f[i1][j]+ijf[i][j]+N2(i+j)Nij

可以直接用两个循环解决,下面的代码中采用的是记忆化搜索。


#include<stdio.h>
#define MAXN 2005

int N,M,R,C;
bool row[MAXN],col[MAXN];
double w[MAXN][MAXN];

void DFS(int c,int r)
{
    if(w[c][r]!=-1)return;
    if(c==0&&r==0){w[c][r]=0;return;}

    double ans=0;
    if(c)DFS(c-1,r),ans+=(c*N-c*r)*w[c-1][r];
    if(r)DFS(c,r-1),ans+=(r*N-c*r)*w[c][r-1];
    if(c&&r)DFS(c-1,r-1),ans+=c*r*w[c-1][r-1];
    w[c][r]=1.0*(ans+N*N)/((c+r)*N-c*r);
}

int main()
{
    int i,j,x,y;

    scanf("%d%d",&N,&M);
    for(i=1;i<=M;i++)
    {
        scanf("%d%d",&x,&y);
        col[x]=true;
        row[y]=true;        
    }

    for(i=1;i<=N;i++)if(!col[i])C++;
    for(i=1;i<=N;i++)if(!row[i])R++;

    for(i=0;i<=N;i++)
    for(j=0;j<=N;j++)w[i][j]=-1;

    DFS(C,R);

    printf("%.2lf",w[C][R]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值