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\n",a[k]/c[n][k]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/7918615.html

时间: 2024-10-27 08:33:48

HihoCoder 1075 开锁魔法III(概率DP+组合)的相关文章

hihocoder 1075 开锁魔法III(置换+DP)

这题先预处理数组有多少个置换,这样的话,每个置换最少要被选到一次,最多就是置换长度的次数,利用这些置换进行DP,和背包一样的,每个置换当成一个物品,选择的概率很容易算出,利用这点进行状态转移即可算出种数,最后在除上总情况数就可以算出概率 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int N

[ACM] hihoCoder 1075 开锁魔法III (动态规划,组合数学)

描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数 T (T ≤ 100)表示数据组数. 对于每组数据,第一行有两个整数 n 和 k (1?≤?n?≤?300,?0?≤?k?≤?n). 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 a

hihoCoder - 1075 开锁魔法III

Description 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 \(n(n\le 300)\) 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 \(k\) 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? Solution 这 gay 题. 把 \(i\) 连向 \(a_i\) ,就成了若干简单环.只要最开始打开一个环内任何一个点,就可以打开整个环. 令每个环大小为 \(s

[dp+组合数学] hihocoder 1075 开锁魔法III

题意: 中文题~ 思路: 首先需要处理的就是把所有的环找出来 环的意思就是这个环里面只要有一个盒子被打开了,其他盒子就都被打开了. 比如样例.就是有两个环(1,2,5) 和 (3,4)并记录环内盒子的总数. 这样就转换成了这样的一个问题了. 给n堆东西,每堆有ai个,问现在取k次,保证每堆至少取1个的方案数. 然后总的方案数是C[n][k].概率一除就好了. 那么这个方案数怎么求呢. 我们就要设dp[i][j]代表花j个钥匙开前i个环的方案数. 那么转移的话就是 dp[i][j]=Σ dp[i-

Hihocoder #1075 : 开锁魔法III (组合数学+动态规划)

题目链接 题目大意:有n个箱子,每个箱子中放着一个箱子的钥匙,可以用魔法打开k个箱子,问最终能打开所有箱子的概率是多少. 思路:首先我们想到,如果一组箱子的打开目标能构成一个环,那么这个箱子中只要打开一个就随意了.问概率的话,最好想的做法就是用A事件发生的次数/事件总数.事件总数很好求,就是在n个箱子中选择k个打开:C[n][k]. 然后考虑有多少种合法的打开方式,我开始想的是直接用组合数学乱搞,乘法原理,设一共有tot个环,每个环的大小分别是a1,a2,a3...atot;计算的时候先a1*a

#1075 : 开锁魔法III

描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数 T (T ≤ 100)表示数据组数. 对于每组数据,第一行有两个整数 n 和 k (1 ≤ n ≤ 300, 0 ≤ k ≤ n). 第二行有 n 个整数 ai,表示第 i 个盒子中,装有可以打开第 a

Hiho #1075: 开锁魔法III

Problem Statement 描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它们打开.崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗? 输入 第一行一个整数$T$ ($T \leq 100$)表示数据组数. 对于每组数据,第一行有两个整数$n$和$k$ ($1 \leq n \leq 300, 0 \leq k \leq 

哈理工2249开锁魔法 概率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

开锁魔法II 哈尔滨理工大学第五届ACM程序设计竞赛

规律:a[i][j]=     1/i * a[i-1][j-1]      +      (i-1)/i * a[i-1][j];  (少一个盒子时使用j-1 次魔法的概率)   (少一个盒子时使用j次魔法的概率) 公式推导如下: 设a[i][j]为打开i个盒子正好需要j次魔法的情况. ① 1->1 ② 1->1 , 2->2;        两次 1->2 , 2->1;        一次 ③ 1->1 , 2->2 , 3->3;     三次 1-