BNU 1084 Expected Allowance (dp||母函数||深搜)

题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=1084

题目大意:给你n个骰子,每个骰子有m个面,点数分别为(1-m),现在同时摇这n个骰子,(得到的点数和)-k  即为小明得到的钱数,当然小明每次最少会得到一元(即最后结果小于等于1时),问小明得到钱数的期望值。

解题思路:由于此题m*n较小,故按照普通的期望计算就行,即   摇到某个点数(i)的概率p*摇到的点数(i),其中显然(n=<  i  <=n*m)除以总的情况数(m的n次方)(每次都有m种可能);  那么此题的重点就是求(n到n*m每个数被分成n份的分法),其中 (1 1 4 和1 4 1 和4 1 1为不同的分法)。

法一:深搜(比较暴力)

///n个骰子,每个骰子有(1-m)种权值,随意组合
///直到n个骰子用完,得到的点数和即为当前组合的期望,
///深搜递归所有的组合,即得到ans
#include<cstdio>
#include<cmath>
///n为剩余骰子数,sum为已选(m-n)个骰子的和
int dfs(int n,int m,int k,int sum)
{
    int ans=0;
    if(n==0) ans+=sum>k?sum-k:1;
    else
    {
        for(int i=1;i<=m;i++)
        ans+=dfs(n-1,m,k,sum+i);
    }
    return ans;
}
int main()
{
    int n,m,k;
    while(scanf("%d%d%d",&n,&m,&k),(n+m+k))
    {
        printf("%.10lf\n",dfs(n,m,k,0)/pow(m,n));
    }
    return 0;
}

法二:母函数

关于母函数的基础知识,详见http://blog.csdn.net/u011632342/article/details/24269401

其中代码中的c1[ k ] ,存储的是n个骰子摇到和为k的方案数,故最后的结果要   sigma(方案数*权值)/总方案数

///对于基础母函数,就是处理组合一类的问题,但基础母函数对于一个物品可以选择不选(即权值为0)
///但在此题中,每次摇骰子,每个骰子的点数肯定不为0,这点需要初始化,循环时也要注意
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

int c1[1000005],c2[100005];         ///c1为结果数组,c2为中间结果数组
int main()
{
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k),(n+m+k))
    {
        memset(c1,0,sizeof(c1));
        for(int i=1;i<=m;i++)        ///对于第一个骰子初始化
            c1[i]=1;
        memset(c2,0,sizeof(c2));
        for(int i=2;i<=n;i++)         ///因子的个数,即骰子的个数(第一个骰子已经初始化)
        {
            for(int j=1;j<=m;j++)    ///每个因子的每一项,即骰子的每个面的权值(从1循环)
            {
                for(int kk=1;kk+j<=i*m;kk++)   ///c1数组的每一项(从1开始),即当前能组成的点数都要循环
                    c2[kk+j]+=c1[kk];
            }
            memcpy(c1,c2,sizeof(c2));///拷贝函数
            memset(c2,0,sizeof(c2));
        }
        double sum=0;
        for(int i=n; i<=n*m; i++)
            sum+=(i>k?c1[i]*(i-k):c1[i]);
        printf("%.9lf\n",sum/pow(m,n));
    }
    return 0;
}

法三:DP

///dp思想类似于母函数,其中dp[j]表示n个骰子摇到和为j的种数
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int dp[100005];

void fun(int n,int m)
{
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=m; i++)  ///初始化第一枚骰子
        dp[i]=1;
    for(int i=2; i<=n; i++)   ///总骰子数
        for(int j=i*m; j>=i; j--) ///前i枚骰子的点数区间,此处要倒序求dp[j]
        {
            int a=0;
            for(int k=1; k<=m; k++)   ///每种情况下骰子的可能的面值
            {
                if((j-k)<=(i-1)*m&&(j-k)>=i-1)  ///前i个骰子的值-第i个骰子的值 出现在 前i-1个骰子的和里
                a+=dp[j-k];                    ///a用来统计有多少种方法能到达 j
            }
            dp[j]=a;
        }
}
int main()
{
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k),(n+m+k))
    {
        fun(n,m);
        double ans=0;
        for(int i=n; i<=n*m; i++)
            ans+=dp[i]*(i-k>0?i-k:1);
        printf("%.9lf\n",ans/pow(m,n));
    }
    return 0;
}

时间: 2024-11-09 09:44:13

BNU 1084 Expected Allowance (dp||母函数||深搜)的相关文章

【组队赛#8】BNU 1084 Expected Allowance (母函数)

[题目链接]click here~~ [题目大意]给出一个n个骰子,每个骰子有m个面,给出一个削减值k,投掷一次,所有的骰子点数和要减去k,如果减去的值小于1,则得到的钱也至少是1:要求出他能得到钱的期望值 [解题思路]母函数!!,关键在于理解题意思路:(每个点数出现的概率要计算) 具体看代码吧 母函数: #include <bits/stdc++.h> #include <iostream> #include <string.h> #include <stdio

嵌套矩形 DAG上的dp(深搜+dp)

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=16 矩形嵌套 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c,b<d或者b<c,a<d(相当于旋转X90度).例如(1,5)可以嵌套在(6,2)内,但不能嵌套在(3,4)中.你的任务是选出尽可能多的矩形排成一行,使得除最后一个外,每一

方格取数(多线程dp,深搜)

https://www.luogu.org/problem/P1004 题目描述 设有N×N的方格图(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示(见样例): 某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角的B点.在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0).此人从A点到B点共走两次,试找出2条这样的路径,使得取得的数之和为最大. 输入格式 输入的第一行为一个整数N(表示N×N的方格图),接下来的每行有三个整数,前

2015暑假多校联合---Mahjong tree(树上DP 、深搜)

题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5379 Problem Description Little sun is an artist. Today he is playing mahjong alone. He suddenly feels that the tree in the yard doesn't look good. So he wants to decorate the tree.(The tree has n

ZOJ1100 状压DP +深搜

记得做过类似于这类题目是可以用组合数学方法来解决的,可惜淡忘了,也找不到了,看了网上的也有人提到过可以用组合公式解决,可是没人做,都是用了状压DP的方法,这个状压很难讲清楚吧,推荐两篇 第一遍大体看看这个:http://blog.csdn.net/crux_d/article/details/2206736 想要具体实现的时候看看他的解析:http://blog.csdn.net/yan_____/article/details/8719748 #include<iostream> #incl

hdu--1520--树形dp&lt;写起来就是深搜啊&gt;

我肯定还没怎么理解树形dp啊...为什么写下去 就感觉是多了个状态转移方程的深搜呢?或者因为树形dp是依托在树这个数据结构上所进行的 所以是这样的? 这题 被很多人 当做树形dp的入门题 的确.... 如果 u 是 v 的前驱即父母 那么 dp[u][0] += max( dp[v][1] , dp[v][0] ) 0表示u不包括在内 1在内 dp[u[[1] += dp[v][0] 不太难写 还好这个 主要是 每个树形dp都要找出根结点 因为数据很宽松 我直接用了vector来写 1 #inc

深搜+DP剪枝 codevs 1047 邮票面值设计

codevs 1047 邮票面值设计 1999年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一个信封,最多只允许粘贴N张邮票,计算在给定K(N+K≤40)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值MAX,使在1-MAX之间的每一个邮资值都能得到. 例如,N=3,K=2,如果面值分别为1分.4分,则在1分-6分之间的每一个邮资值都能得到(当然还有8分.9分和1

hdu 5311 Hidden String dp o(n)算法 深搜

Hidden String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 857    Accepted Submission(s): 322 Problem Description Today is the 1st anniversary of BestCoder. Soda, the contest manager, gets

ACM 海贼王之伟大航路(深搜剪枝)

"我是要成为海贼王的男人!" 路飞他们伟大航路行程的起点是罗格镇,终点是拉夫德鲁(那里藏匿着"唯一的大秘宝"--ONE PIECE).而航程中间,则是各式各样的岛屿. 因为伟大航路上的气候十分异常,所以来往任意两个岛屿之间的时间差别很大,从A岛到B岛可能需要1天,而从B岛到A岛则可能需要1年.当然,任意两个岛之间的航行时间虽然差别很大,但都是已知的. 现在假设路飞一行从罗格镇(起点)出发,遍历伟大航路中间所有的岛屿(但是已经经过的岛屿不能再次经过),最后到达拉夫德鲁