#1075 : 开锁魔法III

来源:互联网 发布:淘宝网买电动车可靠吗 编辑:程序博客网 时间:2024/04/29 16:51

描述

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

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

输入

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

输出

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

样例输入
45 12 5 4 3 15 22 5 4 3 15 32 5 4 3 15 42 5 4 3 1
样例输出
0.0000000000.6000000000.900000000

1.000000000

#include <iostream> #include <map>#include <vector>#include <string>#include <cstring>using namespace std;int math[302];int visit[302];double c[320][320];double dp[320][320];vector<int>loop;void Count(){for(int i=0;i<=300;i++){c[i][0]=c[i][i]=1.0;for(int j=1;j<i;j++){c[i][j]=c[i-1][j-1]+c[i-1][j];}}}int main(){Count();int t;cin>>t;while(t--){int n,k;cin>>n>>k;for(int i=1;i<=n;i++){cin>>math[i];}loop.clear();memset(visit,0,sizeof(visit));int cur=0;for(int i=1;i<=n;i++){if(visit[i])continue;cur=0;int cnt=i;while(!visit[cnt]){visit[cnt]=1;cnt=math[cnt];cur++;}loop.push_back(cur);}int num=loop.size();if(num>k){printf("%.9lf\n",0.0);continue;}memset(dp,0,sizeof(dp));dp[0][0]=1.0;for(int i=0;i<num;i++){for(int j=0;j<k;j++){if(dp[i][j]==0)continue;for(int use=1;use<=loop[i]&&j+use<=k;use++){dp[i+1][j+use]+=dp[i][j]*c[loop[i]][use];}}}printf("%.9lf\n",dp[num][k]/c[n][k]);}}

0 0