zoukankan      html  css  js  c++  java
  • ZOJ 3329 One Person Game

    题意:给定n,k1,k2,k3,a,b,c七个数。有三个骰子,第一个骰子有k1个面,第二个有k2个面,第三个有k3个面,摇骰子得到的点数即为摇动后向上的面的点数,每一个面向上的概率相同。一个人的分数记为count,初始时count=0,然后同时摇三个骰子记为一次摇动,每次摇动之后,三个骰子分别得到x1,x2,x3点,若x1=a且x2=b且x3=c,则count=0,否则,count += x1+x2+x3。若count > n,则游戏结束,否则继续游戏。问摇动次数的期望。

    解法:在做了POJ 2096 Collecting Bugs之后,已经大概懂得怎样用DP处理期望问题了。DP求概率要正推,求期望要倒推。

       但是,当我写出状态转移的方程的时候,又发现了一个新问题,就是这道题是带环的期望问题。一般而言,带环的问题都要用高斯消元来做,但这道题其实不用那么麻烦。

       设E[i]表示count = i的情况下,平均还需要摇多少次骰子,才能结束游戏。p[i]表示摇骰子后count需要加i分的概率,p[0]表示摇骰子后count置0的概率。

       状态转移方程为:E[i] = E[i+1]*p(1) + E[i+2]*p(2) + E[i+3]*p[3].....+E[i+k]*p[k] + E[0]*p[0] + 1。

       可以发现,每个状态转移方程的未知量都是E[0],所以这道题就有了下面解法:

       设E[i] = a[i]*E[0] + b[i],则由上面的状态转移方程又有E[i] = (segma(a[i+x]*p[x]) + p[0]) * E[0] + segma(b[[i+x]*p[x]) + 1。

       所以有a[i] = segma(a[i+x]*p[x]) + p[0],b[i] = segma(b[i+x]*p[x]) + 1。而答案E[0] = b[0] / (1-a[0])。这样就可以用DP解决问题了。

    tag:math, 概率DP, 代数变形

     1 /*
     2  * Author:  Plumrain
     3  * Created Time:  2013-10-30 09:57
     4  * File Name: math-ZOJ-3329.cpp
     5  */
     6 #include<iostream>
     7 #include<cstdio>
     8 #include<cstring>
     9 
    10 using namespace std;
    11 
    12 #define CLR(x) memset(x, 0.0, sizeof(x))
    13 
    14 int n, tot;
    15 double p[20], a[1000], b[1000];
    16 
    17 void init()
    18 {
    19     int k[3], tmp, sum = 0;
    20     scanf ("%d", &n);
    21     for (int i = 0; i < 3; ++ i)
    22             scanf ("%d", &k[i]);
    23     for (int i = 0; i < 3; ++ i){
    24         scanf ("%d", &tmp);
    25         sum += tmp;
    26     }
    27 
    28     int num[20]; CLR (num);
    29     for (int i = 1; i <= k[0]; ++ i)
    30         for (int j = 1; j <= k[1]; ++ j)
    31             for (int l = 1; l <= k[2]; ++ l)
    32                 ++ num[i+j+l]; 
    33     -- num[sum];
    34 
    35     int mul = k[0] * k[1] * k[2];
    36     tot = k[0] + k[1] + k[2];
    37     num[0] = 1;
    38     for (int i = 0; i <= tot; ++ i)
    39         p[i] = (double)num[i] / mul;
    40 }
    41 
    42 double DP()
    43 {
    44     CLR (a); CLR (b);
    45     for (int i = n; i >= 0; -- i){ 
    46         a[i] = p[0];
    47         b[i] = 1.0;
    48         for (int j = 1; j <= tot; ++ j){
    49             a[i] += a[i+j] * p[j];
    50             b[i] += b[i+j] * p[j];
    51         }
    52     }
    53     
    54     return b[0] / (1 - a[0]);
    55 }
    56 
    57 int main()
    58 {
    59     int T;
    60     scanf ("%d", &T);
    61     while (T--){
    62         init();
    63         printf ("%.10f
    ", DP());
    64     }
    65     return 0;
    66 }
    View Code
    ------------------------------------------------------------------
    现在的你,在干什么呢?
    你是不是还记得,你说你想成为岩哥那样的人。
  • 相关阅读:
    用cascade删除有约束的表或记录
    易混淆的Window窗体与父窗体之间位置关系
    界面主窗体,子窗体的InitializeComponent(构造函数)、Load事件执行顺序
    DEV CheckComboboxEdit、CheckedListBoxControl(转)
    程序实现DataGrid过滤设置
    创建触发器的基本语法
    查看dll中的函数(方法)
    delphi xe2 64位嵌入汇编问题 https://bbs.csdn.net/topics/390333981
    USB转换PS2接线原理
    Win8.1+VS2013+WDK8.1+VirtualBox or VMware 驱动开发环境配置
  • 原文地址:https://www.cnblogs.com/plumrain/p/ZOJ_3329.html
Copyright © 2011-2022 走看看