码迷,mamicode.com
首页 > 其他好文 > 详细

哈理工2249开锁魔法 概率dp

时间:2015-04-12 00:07:26      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:概率dp

开锁魔法II
Time Limit: 3000 MS Memory Limit: 256000 K
Total Submit: 23(18 users) Total Accepted: 18(16 users) Rating: 技术分享技术分享 Special Judge: No
Description
一日,崔克茜来到小马镇表演魔法。
其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它。崔克茜可以通过魔法,暴力打开一个盒子。但是崔克茜最多只可以使用 k 次魔法,问在 k 次魔法内,打开所有盒子的概率是多少。
Input
多组测试数据。
每组数据第一行有一个整数 n 和一个整数 k。(1 <= k <= n?<= 5000)
Output
对于每组数据,输出一行表示对应的答案。结果保留四位小数。
Sample Input
3 1
3 2
3 3
10 3
Sample Output
0.3333
0.8333
1.0000
0.7061
Source
哈尔滨理工大学第五届ACM程序设计竞赛
Submit Statistic Discuss Sharedcodes



令d[i][j]表示前i把锁必须要用j次魔法打开的概率,不难看出dp[i][j]转移有两个来源,一个是前i-1把锁用了j次魔法,此时打开的前i-1个箱子里一定有一把钥匙是第i个箱子的(否则无法在j次魔法的情况下打开第i个盒子),概率为(i-1)/i,另一种情况就是前i-1个箱子用了j-1次魔法,前i-1个箱子里的钥匙一定不能打开第i把锁(否则只需要j-1次魔法就能打开前i个箱子),概率为1/i。最后的结果应该是d[n][1]+d[n][2]+...d[n][k]。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const int maxn = 5e3 + 5;
double d[maxn][maxn];
void init(int n)
{
    memset(d,0,sizeof d);
    d[0][0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= i; ++j) {
            d[i][j] = (d[i-1][j]*(i-1)+d[i-1][j-1])/i;
        }
    for(int i = 2;i <= n; ++i)
        for(int j = 1; j <= i; ++j)
            d[i][j] += d[i][j-1];
}
int main(int argc, char const *argv[])
{
    int n,k;
    init(5000);
    while(~scanf("%d%d",&n,&k))
        printf("%.4f\n",d[n][k]);
    return 0;
}


哈理工2249开锁魔法 概率dp

标签:概率dp

原文地址:http://blog.csdn.net/acvcla/article/details/44999999

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!