zoukankan      html  css  js  c++  java
  • Little Pony and Alohomora Part 3 [HihoCoder 1075]

    描述

    一日,崔克茜来到小马镇表演魔法。

    其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它。初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开。崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗?

    输入

    第一行一个整数 T (T ≤ 100)表示数据组数。 对于每组数据,第一行有两个整数 nk (1 ≤ n ≤ 300, 0 ≤ k ≤ n)。 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 ai 个盒子的钥匙。

    输出

    对于每组询问,输出一行表示对应的答案。要求相对误差不超过四位小数。


    样例输入
        4
        5 1
        2 5 4 3 1
        5 2
        2 5 4 3 1
        5 3
        2 5 4 3 1
        5 4
        2 5 4 3 1

    样例输出
        0.000000000
        0.600000000
        0.900000000
        1.000000000

    分析

    我们设dp [i][j]
    那么前一个状态为 dp [i-1][j-use],即用j-use把钥匙打开前i-1个阶段的盒子一共有的方法数
    也就是说打开第i个阶段的盒子用了use个钥匙,一共有  C(cnt,use)种方法,cnt为第i个阶段一共有cnt个待打开的盒子

    那么根据乘法原理
    dp[i][j]=dp[i-1][j-use]*C(cnt,use) ,
    但是前一个状态不唯一,也就是use的值可以变化,所以要方法累加 即dp[i][j]+=dp[i-1][j-use]*C(cnt,use).  这里dp[i][j]是未知的,要求它就必须知道dp[i-1][j-use],也就是用已知的状态去推出未知的状态。

    代码

     1 #include <iostream>  
     2 #include <stdio.h>  
     3 #include <string.h>  
     4 #include <vector>  
     5 #include <iomanip>  
     6 using namespace std;  
     7 int n,k;  
     8 int match[320];  
     9 double c[320][320];  
    10 bool vis[320];  
    11 double dp[320][320];  
    12 vector<int>loop;     
    13 void getComb()  
    14 {  
    15     for(int i=0;i<=300;i++)  
    16     {  
    17         c[i][0]=c[i][i]=1.0;  
    18         for(int j=1;j<i;j++)  
    19             c[i][j]=c[i-1][j]+c[i-1][j-1];  
    20     }  
    21 }  
    22       
    23 int main()  
    24 {  
    25     getComb();  
    26     int t;  
    27     cin>>t;  
    28     while(t--)  
    29     {  
    30         cin>>n>>k;  
    31         for(int i=1;i<=n;i++)  
    32             cin>>match[i]; 
    33         loop.clear();
    34         memset(vis,0,sizeof(vis));  
    35         for(int i=1;i<=n;i++)//求循环节  
    36         {  
    37             if(vis[i])  continue;  
    38             int cnt=0,cur=i;  
    39             while(!vis[cur])  
    40             {  
    41                 cnt++;  
    42                 vis[cur]=1;  
    43                 cur=match[cur];  
    44             }  
    45             loop.push_back(cnt);  
    46         }  
    47               
    48         int num=loop.size();  
    49         if(k<num)  
    50         {  
    51             printf("%.9lf
    ",0.0);  
    52             continue;  
    53         }  
    54               
    55         memset(dp,0,sizeof(dp));  
    56         dp[0][0]=1.0;  
    57         for(int i=0;i<num;i++)  
    58         {  
    59             for(int j=0;j<k;j++)  
    60             {  
    61                 if(dp[i][j]==0)  continue;  
    62                 for(int use=1;use<=loop[i]&&j+use<=k;use++)  
    63                     dp[i+1][j+use]+=dp[i][j]*c[loop[i]][use]; 
    64             }  
    65         }  
    66         printf("%.9lf
    ",dp[num][k]/c[n][k]);  
    67     }  
    68     return 0;
    69 }  查看代码
    点击查看代码
  • 相关阅读:
    算法洗脑系列(8篇)——第五篇 分治思想
    算法洗脑系列(8篇)——第七篇 动态规划
    算法洗脑系列(8篇)——第四篇 枚举思想
    8天学通MongoDB——第二天 细说增删查改
    12篇学通C#网络编程——第一篇 基础之进程线程
    算法系列15天速成——第十五天 图【下】(大结局)
    算法洗脑系列(8篇)——第一篇 递推思想
    8天学通MongoDB——第三天 细说高级操作
    8天学通MongoDB——第四天 索引操作
    算法洗脑系列(8篇)——第八篇 概率思想
  • 原文地址:https://www.cnblogs.com/ibilllee/p/7649918.html
Copyright © 2011-2022 走看看