[CLYZ2017]day3
最大割
solution
100分
待我学完线性基.
开锁
solution
100分
每个点只有一条出边和入边,显然图由很多个环组成.
每个环中必须选出一个点,才能打开所有的箱子.
预处理出每个环的大小,设共\(m\)个,大小为\(g_i\).
\(f[i][j]\)表示前\(i\)个环选了\(j\)个点合法的方案数.
\(f[i][j]=\sum_{l=1}^{g_i}f[i-1][j-l]\times{C_{g_i}^l}\)
\(ans=\frac{f[m][k]}{C_n^k}\).
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 305
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
using namespace std;
typedef long long ll;
int a[N],g[N],n,k,t,cnt;
bool v[N];
double f[N][N],c[N][N];
inline void Aireen(){
scanf("%d",&t);
for(int i=0;i<N;++i)
c[i][0]=1.0;
for(int i=1;i<N;++i)
for(int j=1;j<=i;++j)
c[i][j]=c[i-1][j-1]+c[i-1][j];
while(t--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
cnt=0;memset(v,0,sizeof(v));
for(int i=1;i<=n;++i)
if(!v[i]){
v[i]=true;g[++cnt]=1;
for(int j=a[i];j!=i;j=a[j]){
v[j]=true;++g[cnt];
}
}
for(int i=1;i<=cnt;++i)
for(int j=1;j<=cnt;++j)
f[i][j]=0.0;
memset(f,0.0,sizeof(f));
f[0][0]=1.0;
for(int i=1;i<=cnt;++i){
for(int j=i,q;j<=k;++j)
for(int l=min(g[i],j);l>=1;--l)
f[i][j]+=f[i-1][j-l]*c[g[i]][l];
}
printf("%.6lf\n",f[cnt][k]/c[n][k]);
}
}
int main(){
freopen("unlock.in","r",stdin);
freopen("unlock.out","w",stdout);
Aireen();
fclose(stdin);
fclose(stdout);
return 0;
}