概率DP训练

http://www.codeforces.com/problemset/problem/148/D

题意:

一个袋子里面装有n个小白鼠,m个小黑鼠,A,B两人轮流从中取老鼠,A先取,规定谁先取到白色小鼠谁就赢。B比较特殊,每当他取完一只老鼠时,总是会惊动其他的老鼠,所以取完之后剩下的老鼠会从袋子中溜掉一只。 而对于A取完后不会存在这种情况。问A取胜的概率。

思路:

首先我想了一个4维的dp[i][j][k][2]  i表示到了第几步(这里可以用滚动数组优化,然后就可以存了) j表示还剩下白鼠j只,k表示还剩下黑鼠k只,最后一维: 0 表示取白鼠,1表示取黑鼠,

状态转移就很好想了,就是分取白鼠还是取黑鼠的情况讨论,我想这应该是最笨的方法了吧。不过时间复杂度是不会允许的(O(10^9)),不过我还是试着写了一下,结果到1000 1000 肯定挂了。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1

#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 26
#define N 1007


using namespace std;


const int inf = 0x1F1F1F1F;
const int mod = 1000000007;
const int X = 1000000005;

double dp[2][N][N][2];

int main()
{
    int n,m;
    int i,j,k;
    scanf("%d%d",&n,&m);
    if (n == 0)
    {
        printf("0\n");
        return 0;
    }
    if (m == 0)
    {
        printf("1\n");
        return 0;
    }

    int u = 0,v = 1;

    for (j = n; j >= 0; --j)
    {
        for (k = m; k >= 0; --k)
        {
            dp[u][j][k][0] = dp[u][j][k][1] = 0;
        }
    }
    dp[u][n][m][1] = 1.0;

    double ans = 0;

    for (i = 1; i <= m; ++i)
    {
        for (j = n; j >= 0; --j)
        {
            for (k = m; k >= 0; --k)
            {
                dp[v][j][k][0] = dp[v][j][k][1] = 0;
            }
        }

        for (j = n; j >= 0; --j)
        {
            for (k = m; k >= 0; --k)
            {
                if (dp[u][j][k][1] != 0)
                {
                    if (i % 2 == 0)
                    {
                        if (j - 2 >= 0)
                        {
                            double tmp = 1.0*(j - 1)/(1.0*(j - 1 + k));
                            dp[v][j - 2][k][0] += dp[u][j][k][1]*((1.0*j)/(1.0*(j + k)))*tmp;
                        }
                        if (j - 1 >= 0 && k - 1 >= 0)
                        {
                            double tmp = 1.0*k/(1.0*(k + j - 1));
                            dp[v][j - 1][k - 1][0] += dp[u][j][k][1]*((1.0*j)/(1.0*(j + k)))*tmp;
                        }
                    }
                    else if (i % 2 == 1 && j - 1 >= 0)
                    {
                        dp[v][j - 1][k][0] += dp[u][j][k][1]*((1.0*j)/(1.0*(j + k)));
                        ans += dp[u][j][k][1]*((1.0*j)/(1.0*(j + k)));
                    }


                    if (i % 2 == 0)
                    {
                        if (k - 2 >= 0)
                        {
                            double tmp = 1.0*(k - 1)/(1.0*(k - 1 + j));
                            dp[v][j][k - 2][1] += dp[u][j][k][1]*((1.0*k)/(1.0*(j + k)))*tmp;
                        }
                        if (j - 1 >= 0 && k - 1 >= 0)
                        {
                            double tmp = 1.0*j/(1.0*(k - 1 + j));
                            dp[v][j - 1][k - 1][1] += dp[u][j][k][1]*((1.0*k)/(1.0*(j + k)))*tmp;
                        }
                    }
                    else if (i % 2 == 1 && k - 1 >= 0)
                    dp[v][j][k - 1][1] += dp[u][j][k][1]*((1.0*k)/(1.0*(j + k)));

//                    cout<<"Ans = "<<ans<<endl;


                }
            }
        }
//        for (j = 0; j <= n; ++j)
//        {
//            for (k = 0; k <= m; ++k)
//            {
//                printf("%.3lf ",dp[v][j][k][0]);
//            }
//            printf("\n");
//        }
//        printf("\n******************\n");
//        for (j = 0; j <= n; ++j)
//        {
//            for (k = 0; k <= m; ++k)
//            {
//                printf("%.3lf ",dp[v][j][k][1]);
//            }
//            printf("\n");
//        }
        swap(u,v);
    }

    printf("%.9lf\n",ans);
    return 0;
}

 

再想如何维数优化呢? n m <= 1000所以我们可以试着压缩一维然后就是(O(2*10^6))了,我们注意到只要记录到这一步时,选择多少,和剩下的白色小鼠的个数即可。

dp[i][j][2] i表示到了第几步, j表示还剩下j只小鼠还没有取出,最后一维表达的意思还是一样。  tot记录小鼠的总数,sub记录一共选择了多少。

然后黑鼠的个数就是 tot - sub - j了。

View Code
//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1

#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 26
#define N 1007


using namespace std;


const int inf = 0x1F1F1F1F;
const int mod = 1000000007;
const int X = 1000000005;

double dp[2][N][2];

int main()
{
    int n,m;
    int i,j;
    scanf("%d%d",&n,&m);
    double tot = n + m;
    if (n == 0)
    {
        printf("0\n");
        return 0;
    }
    if (m == 0)
    {
        printf("1\n");
        return 0;
    }

    int u = 0,v = 1;

    for (j = n; j >= 0; --j)
    {
        dp[u][j][1] = dp[u][j][0] = 0;
    }
    dp[u][n][1] = 1.0;

    double ans = 0;
    double tmp = 0;
    double sub = 0;

    for (i = 1; i <= m; ++i)
    {
        for (j = n; j >= 0; --j)
        {
            dp[v][j][0] = dp[v][j][1] = 0;
        }

        for (j = n; j >= 0; --j)
        {
            if (dp[u][j][1] != 0)
            {
                //B取
                if (i%2 == 0)
                {
                    //取白鼠,溜走的也是白鼠
                    if (j - 2 >= 0 && (tot - sub - 1) > 0)
                    {
                        tmp = (1.0*(j - 1))/(tot - sub - 1);
                        dp[v][j - 2][0] += dp[u][j][1]*((1.0*j)/(tot - sub))*tmp;
                    }

                     //取白鼠,溜走的也是黑鼠
                    if (j - 1 >= 0 && (tot - sub - 1) > 0)
                    {
                        tmp = (1.0*(tot - sub - j))/(tot - sub - 1);
                        dp[v][j - 1][0] += dp[u][j][1]*((1.0*j)/(tot - sub))*tmp;
                    }
                    
                     //取黑鼠,溜走的也是白鼠
                    if (j - 1 >= 0 && tot - sub - 1 > 0)
                    {
                        tmp = 1.0*(j)/(tot - sub - 1);
                        dp[v][j - 1][1] += dp[u][j][1]*(1.0*(tot - sub - j)/(tot - sub))*tmp;
                    }
                    //取黑鼠,溜走的也是黑鼠
                    if (tot - sub - 1 > 0)
                    {
                        tmp = 1.0*(tot - sub - j - 1)/(tot - sub - 1);
                        dp[v][j][1] += dp[u][j][1]*(1.0*(tot - sub - j)/(tot - sub))*tmp;
                    }
                }//A取
                else
                {
                    //取白鼠
                    if (j - 1 >= 0)
                    {
                        dp[v][j - 1][0] += dp[u][j][1]*((1.0*j)/(tot - sub));
                        ans += dp[u][j][1]*((1.0*j)/(tot - sub));
                    }
                    //取黑鼠
                    dp[v][j][1] += dp[u][j][1]*(1.0*(tot - sub - j)/(tot - sub));
                }
            }
        }

        if (i % 2 == 0) sub += 2;
        else sub += 1;

        swap(u,v);
    }
    printf("%.9lf\n",ans);
    return 0;
}

 

后来看了一下牛人的代码,惭愧啊。直接一个二维DP,然后记忆化搜索搞定,我搞的有一百多行,人家就几十行。膜拜啊。

dp[i][j]表示剩下i个白鼠,j个黑鼠

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1

#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 26
#define N 1007


using namespace std;


const int inf = 0x1F1F1F1F;
const int mod = 1000000007;
const int X = 1000000005;

double dp[N][N];
double eps = 1e-10;
int dblcmp(double x)
{
    if (x > eps) return 1;
    else if (x < -eps) return -1;
    else return 0;
}

double DP(int n,int m)
{

    if (n <= 0 || m < 0) return 0.0;
    if (m == 0) return 1.0;
    if (dp[n][m] > 0) return dp[n][m];

    double dn = n,dm = m;

    dp[n][m] = dn/(dn + dm);

    if (n + m - 2 > 0)
    {
        dp[n][m] += (dm/(dn + dm)*(dm - 1.0)/(dn + dm - 1.0)) * ((dm - 2.0)/(dn + dm - 2.0)*DP(n,m - 3) + dn/(dn + dm - 2.0)*DP(n - 1,m - 2));
    }
    return dp[n][m];
}
int main()
{
    int n,m;
    int i,j;
    scanf("%d%d",&n,&m);
    for (i = 0; i <= n; ++i)
    {
        for (j = 0; j <= m; ++j)
        {
            dp[i][j] = 0;
        }
    }
    printf("%.9lf\n",DP(n,m));
    return 0;
}

 

sgu http://acm.sgu.ru/problem.php?contest=0&problem=495

/*************************************************************************
题意:
m个人,n个奖品放在n个盒子里面,m个人轮流取盒子拿奖品,每个人取每个盒子的概率是一样的。当人i取盒子的时候可能取到已经被取过的,所以他不会得到奖品,问m个人取盒子,求所有人取到奖品的数学期望。
思路:
才开始理解错题意以为是求取到的奖品个数的数学期望,这里是求的取的盒子的数学期望。每个人要么取到奖品,要么取不到只有两中情况,dp[i]表示第i个人取到奖品的概率,dp[i] = (1 - dp[i - 1])*dp[i - 1] + dp[i - 1]*(dp[i - 1] - 1/n); 表示当第 i - 1个人取不到时的,我取道奖品的概率就是dp[i - 1].如果上一个人取道了奖品,那么我取到的概率为dp[i - 1] - 1/n ; 因为减少了可取的奖品。
这里还可以逆向来向每个精品不被取到的概率为p = ((n - 1)/n)^m 然后算出不被取到的数学期望 n*p 最后 n - n*p 就是被选到的数学期望了。
 
************************************************************************/ 
View Code
#include<iostream>
#include <cstdio>
#include <string>
using namespace std;
#define N 100007


double  dp[N];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    double ans = 1;
    dp[1] = 1; dp[0] = 0;
    for (int i = 2; i <= m; ++i)
    {
        dp[i] = (1 - dp[i - 1])*dp[i - 1] + dp[i - 1]*(dp[i - 1] - 1.0*1/n);
        ans += dp[i];
    }
    printf("%.9lf\n",ans);
    return 0;
}

 

zoj 3380 Patchouli's Spell Cards 

题意:

有m种不同的元素,每种元素都有n种不同的相位,现在假设有每种元素各一个,其相位是等概率随机的。如果几个元素的相位相同,那么帕琪就可以把它们组合发动一个符卡(Spell Card)。现在问帕琪能够发动等级不低于l,即包含大于等于l个相同相位的不同元素的附卡的概率。

思路:

才开始我是推出了组合数的公式,用java的大数写的。不知道为什么不对。后来看了一下解题报告,发现只有l < m/2时用组合公式算是对的。否则要用dp来算,不清楚为什么,好像解题报告也没说可能是中间计算数据溢出吧。这里我们吧把问题转为求m个位置,每个位置是1到n的一个数,问没有l个位置数相同的方案数

dp[i][j]表示前i个相位占据了j个位置,  dp[i][j]+= dp[i - 1][j - k]*C[m - (j - k)][k] 等于前i - 1个占据j - k 个位置的情况诚意在从剩下的空位中占据k个位置

View Code
import java.math.BigInteger;
import java.util.Scanner;

public class Main {

    // public static BigInteger gcd(BigInteger a,BigInteger b)
    // {
    // if (b.compareTo(BigInteger.ZERO) == 0) return a;
    // else return gcd(b,a.mod(b));
    // }

    public static void main(String args[]) {
        BigInteger c[][] = new BigInteger[107][107];

        for (int i = 0; i <= 100; ++i)
            c[i][i] = c[i][0] = BigInteger.ONE;
        for (int i = 2; i <= 100; ++i) {
            for (int j = 1; j < i; ++j) {
                c[i][j] = c[i - 1][j - 1].add(c[i - 1][j]);
            }
        }
        Scanner cin = new Scanner(System.in);
        int n, m, l;

        while (cin.hasNext()) {
            m = cin.nextInt();
            n = cin.nextInt();
            l = cin.nextInt();

            if (l > m) {
                System.out.println("mukyu~");
                continue;
            }
            BigInteger fm = BigInteger.valueOf(n);
            fm = fm.pow(m);
            BigInteger fz = BigInteger.ZERO;
            if (l > m / 2) {
                for (int i = l; i <= m; ++i){
                    BigInteger tmp = c[m][i];
                    BigInteger tp = BigInteger.valueOf(n - 1);
                    tp = tp.pow(m - i);
                    fz = fz.add(tp.multiply(tmp));
                }
                fz = fz.multiply(BigInteger.valueOf(n));
                BigInteger t = fz.gcd(fm);
                System.out.println(fz.divide(t) + "/" + fm.divide(t));
            }
            else{
                BigInteger dp[][] = new BigInteger[107][107];
                for (int i = 0; i <= 100; ++i){
                    for (int j = 0; j <= 100; ++j){
                        dp[i][j] = BigInteger.ZERO;
                    }
                }
                dp[0][0] = BigInteger.ONE;
                for (int i = 1; i <= n; ++i){
                    for (int j = 0; j <= m; ++j){
                        for (int k = 0; k < l && k <= j; ++k){
                            dp[i][j] = dp[i][j].add(dp[i - 1][j - k].multiply(c[m - (j - k)][k]));
                        }
                    }
                }
//                if (n > m) n = m;
                fz = fm.subtract(dp[n][m]);
                BigInteger t = fz.gcd(fm);
                System.out.println(fz.divide(t) + "/" + fm.divide(t));
            }
        }
    }
}

 上边的时间复杂度为O(n*m*l),我们可以优化到O(min(n,m)*m*l) 的,dp[i][j]表示的是用i个相位占据j个位置的情况数,dp[i][j] += dp[i - 1][j - k]*C(m - (i - 1),k)*(n - (i - 1)). 这里算的是排列数,所以在最后相加时想除以i的阶乘,转化成组合数即可。

View Code
import java.math.BigInteger;
import java.util.Scanner;

public class Main {

    // public static BigInteger gcd(BigInteger a,BigInteger b)
    // {
    // if (b.compareTo(BigInteger.ZERO) == 0) return a;
    // else return gcd(b,a.mod(b));
    // }

    public static void main(String args[]) {
        BigInteger c[][] = new BigInteger[107][107];
        BigInteger f[] = new BigInteger[107];
        for (int i = 0; i <= 100; ++i) {
            c[i][i] = c[i][0] = BigInteger.ONE;
            f[i] = i == 0 ? BigInteger.ONE : f[i - 1].multiply(BigInteger.valueOf(i));
        }
        for (int i = 2; i <= 100; ++i) {
            for (int j = 1; j < i; ++j) {
                c[i][j] = c[i - 1][j - 1].add(c[i - 1][j]);
            }
        }
        Scanner cin = new Scanner(System.in);
        int n, m, l;

        while (cin.hasNext()) {
            m = cin.nextInt();
            n = cin.nextInt();
            l = cin.nextInt();

            if (l > m) {
                System.out.println("mukyu~");
                continue;
            }
            BigInteger fm = BigInteger.valueOf(n).pow(m);
            
            if (l > m / 2) {
                BigInteger fz = BigInteger.ZERO;
                for (int i = l; i <= m; ++i){
                    BigInteger tmp = c[m][i];
                    BigInteger tp = BigInteger.valueOf(n - 1);
                    tp = tp.pow(m - i);
                    fz = fz.add(tp.multiply(tmp));
                }
                fz = fz.multiply(BigInteger.valueOf(n));
                BigInteger t = fz.gcd(fm);
                System.out.println(fz.divide(t) + "/" + fm.divide(t));
            }
            else{
        
                BigInteger dp[][] = new BigInteger[107][107];
                
                for (int i = 0; i <= 100; ++i){
                    for (int j = 0; j <= 100; ++j){
                        dp[i][j] = BigInteger.ZERO;
                    }
                }
                
                BigInteger fz = BigInteger.ZERO;
                dp[0][0] = BigInteger.ONE;
                for (int i = 0; i < n && i < m; ++i){
                    for (int j = 0; j < m; ++j){
                        if (dp[i][j].signum() == 0) continue;
                        for (int k = 1; k < l && j + k <= m; ++k){
                            dp[i + 1][j + k] = dp[i + 1][j + k].add(dp[i][j].multiply(c[m - j][k].multiply(BigInteger.valueOf(n - i))));
//                            dp[i + 1][j + k] = dp[i + 1][j + k].add(dp[i][j].multiply(c[m - j - 1][k - 1].multiply(BigInteger.valueOf(n - i))));
                        }
                    }
                }
                
                for (int i = 1; i <= m; ++i){
                    fz = fz.add(dp[i][m].divide(f[i]));
                }
                
                fz = fm.subtract(fz);
                BigInteger t = fz.gcd(fm);
                System.out.println(fz.divide(t) + "/" + fm.divide(t));
            }
        }
    }
}

 

 zoj 3640 Help Me Escape

题意:

一个吸血鬼,每次可以随机的选择n个洞中的任意一个,如果该吸血鬼的攻击值大于 该洞c[i]那么直接可以花费t[i]的时间就可以出去,不然要奋斗一天该吸血鬼攻击值增加c[i],然后再]随机选择n个洞口,问该吸血鬼掏出该洞所需要的天数的数学期望。

思路:
dp[i]表示当吸血鬼拥有攻击值为i为逃出迷宫所需天数的数学期望 if(i > k) dp[i] += t[i]  else dp[i] += DP(i + c[i]) + 1;

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 107
#define N 2000007

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;


double dp[N];
bool vt[N];
int c[M];
int t[M];
int n,m;

double DP(int f)
{
    if (vt[f]) return dp[f];
    vt[f] = true;
    dp[f] = 0;
    for (int i = 0; i < n; ++i)
    {
        if (f > c[i]) dp[f] += t[i];
        else dp[f] += DP(f + c[i]) + 1;
    }
    return dp[f]/=n;
}
int main()
{
    while (~scanf("%d%d",&n,&m))
    {
        for (int i = 0; i < n; ++i)
        {
            scanf("%d",&c[i]);
        }
        for (int i = 0; i < n; ++i)
        {
            t[i] = (1 + sqrt(5))/2*c[i]*c[i];
        }
        CL(vt,false);
        printf("%.3lf\n",DP(m));
    }
    return 0;
}

 

 hdu 4405 Aeroplane chess

题意:

玩飞行棋,起点为0,通过投掷骰子(数字为1,2,3,4,5,6)来决定做的 步数,假设当前位置为i,掷得j, 则走到i + j。 同时还有一些特别的点,可以直接传送i->j;当我走到>=n的时候就结束,问结束时我投掷骰子次数的数学期望。

思路:

 

这里权值在边上所以是这个方程:

就是利用这个模型计算。

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 107
#define N 100007

using namespace std;

const int inf = 100000007;
const int mod = 1000000007;


double dp[N];
map<int,int> mp;
bool vt[N];

int main()
{
    Read();
    int n,m;
    int i,j;

    while (~scanf("%d%d",&n,&m))
    {
         if (!n && !m) break;
         mp.clear();  CL(vt,false);
         int x,y;
         for (i = 0; i < m; ++i)
         {
             scanf("%d%d",&x,&y);
             mp[x] = y; vt[x] = true;
         }
         for (i = 0; i < n + 6; ++i) dp[i] = 0;

         for (i = n - 1; i >= 0; --i)
         {
             for (j = 1; j <= 6; ++j)
             {
                 int pos = (i + j) > n ? n : i+j;
                 dp[i] += (dp[pos] + 1)/6.0;
             }
             if (vt[i]) dp[i] = dp[mp[i]];
         }
         printf("%.4lf\n",dp[0]);
    }
    return 0;
}

 

 

posted @ 2013-04-30 21:38  E_star  阅读(373)  评论(0编辑  收藏  举报