zoukankan      html  css  js  c++  java
  • HihoCoder 1075 开锁魔法III(概率DP+组合)

    描述

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

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

    输入

    第一行一个整数 T (T ≤ 100)表示数据组数。 对于每组数据,第一行有两个整数 n 和 k (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

    1,每个盒子都有一个入度和一个出度,以之前二分图拆点的经验来看,必然会形成很多个环。

    2,每个环至少选择一个盒子。

    3,每个环至少选择一个盒子的组合数,联想到母函数,组合数。

    4.自由YY。可以DP,但是误差可能大一些。可以全部求出来再除,这样误差小一些。

     (ps:学会了母函数再搞组合是要多一分灵感!弯的four)

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    using namespace std;
    const int maxn=310;
    double c[maxn][maxn];
    double a[maxn],b[maxn]; 
    int loop[maxn],num[maxn],cnt,laxt[maxn],n;
    void init()
    {
         cnt=0;
         for(int i=0;i<=n;i++){
              a[i]=b[i]=num[i]=loop[i]=laxt[i]=0;
         }
    }
    void getc()
    {
         int i,j;
         for(i=1;i<=300;i++){
             c[i][0]=c[i][i]=1.0;
             for(j=1;j<i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
        return ;
    }
    void geta()
    {
        int i,j,k;
        for(i=1;i<=num[1];i++) a[i]=c[num[1]][i],b[i]=0.0;
        for(i=2;i<=cnt;i++){
            for(j=0;j<=n;j++)
              for(k=1;k<=num[i];k++)
                 if(j+k<=n) b[j+k]+=a[j]*c[num[i]][k];//不是+1 
            for(j=0;j<=n;j++){
                a[j]=b[j];
                b[j]=0;
            }
        }
    }
    int main()
    {
        int i,j,T,k;
        scanf("%d",&T);
        getc();//组合数C 
        while(T--){
            scanf("%d%d",&n,&k);
            init();
            for(i=1;i<=n;i++) scanf("%d",&laxt[i]);
            for(i=1;i<=n;i++){//分组 
                if(!loop[i]){
                    ++cnt;
                    for(j=i;;j=laxt[j]){
                        if(loop[j]) break;
                        loop[j]=cnt;
                        num[cnt]++;
                    }
                }
            }
            geta();//保证每个环至少一个的母函数 
            printf("%.9lf
    ",a[k]/c[n][k]);
        }
        return 0;
    }
  • 相关阅读:
    JAVA面试基础
    扔硬币问题
    随机数生成随机数
    囚犯猜帽子问题
    十道智力题(三)
    十道智力题(二)
    十道智力题(一)
    lintcode:排颜色 II
    机器学习中的几个常见概念(持续更新中......)
    如何打印一棵树(Java)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7918615.html
Copyright © 2011-2022 走看看