CLJ就是喜欢出ctsc上讲的东西,看来还是得找时间把他的那几道题做下
首先记f(x)为答案>x的概率,那么把这个东西从0到1积分就是答案了
f(x)<=>边小于x不能使图联通的概率
这个有点难求,考虑求使图联通的概率
记f(s)为集合s联通的概率,那么f(s)=1-sigma(f(s')*(1-x)^cnt) (s'属于s且s'一定包含某点k,cnt为链接s'与Cs s'的边数)
可以发现f(s)是个多项式,就可以积分了
由于还没用上64位评测系统,double还是不能过,只好用__float128,比较慢而已
CODE:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; typedef vector<__float128> ploy; ploy operator + (ploy x,ploy y){ ploy ans(max(x.size(),y.size()),0); for (int i=0;i<ans.size();i++) { if (i<x.size()) ans[i]+=x[i]; if (i<y.size()) ans[i]+=y[i]; } return ans; } ploy operator - (ploy x,ploy y) { ploy ans(max(x.size(),y.size()),0); for (int i=0;i<ans.size();i++) { if (i<x.size()) ans[i]+=x[i]; if (i<y.size()) ans[i]-=y[i]; } return ans; } ploy operator * (ploy x,ploy y) { ploy ans(x.size()+y.size()-1,0); for (int i=0;i<x.size();i++) for (int j=0;j<y.size();j++) ans[i+j]+=x[i]*y[j]; return ans; } bool b[1040]; ploy f[1040],quick[100]; int n,m; struct edges{int x,y;}e[100]; ploy ONE(1,1); inline void print(ploy x){ printf("%d ",x.size()); for (int i=0;i<x.size();i++) printf("%lf ",double(x[i])); printf(" "); } void dp(int x){ if (b[x]) return ; b[x]=1; ploy tmp(0,0); for (int i=1;i<(1<<n);i++) { if (!(i&1)) continue; if ((i&x)!=i) continue; if (i==x) continue; int j=x^i; int cnt=0; for (int k=1;k<=m*2;k++) if (i&(1<<e[k].x)&&j&(1<<e[k].y)) cnt++; dp(i); tmp=tmp+f[i]*quick[cnt]; } f[x]=ONE-tmp; } __float128 cal(ploy x) { __float128 ans=0; for (int i=0;i<x.size();i++) ans+=x[i]*1.0/(i+1); return ans; } int main() { scanf("%d%d",&n,&m); quick[0]=ONE; quick[1]=ploy(2,0); quick[1][0]=1;quick[1][1]=-1; for (int i=2;i<=m;i++) quick[i]=quick[i-1]*quick[1]; for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); x--,y--; e[i*2-1]=(edges){x,y}; e[i*2]=(edges){y,x}; } b[1]=1;f[1]=ONE; dp((1<<n)-1); ploy ans=ONE-f[(1<<n)-1]; printf("%.6lf ",double(cal(ans))); return 0; }