bzoj1417: Pku3156 Interconnect

来源:互联网 发布:未来软件家园 编辑:程序博客网 时间:2024/05/17 16:15

传送门
其实我们不关心联通状态,我们只关心联通块大小。
然后枚举加边情况,
是否连接了不同的联通块。
然后加一个记忆话搜索就可以了

#include<map>#include<cmath>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define vec vector<int>using namespace std;map<vec,double> mp;vec ve;int fa[105],sz[105],all,n,m,x,y;int get(int x){    return fa[x]==x?x:fa[x]=get(fa[x]);}double dp(vec ve){    if (mp.count(ve)) return mp[ve];    if (ve.size()==1) return mp[ve]=0;    int sz=ve.size(),p=0;    for (int i=0;i<sz;i++)        p+=ve[i]*(ve[i]-1)/2;    double ans=1.0*all/(all-p);    for (int i=1;i<sz;i++)        for (int j=0;j<i;j++){            vec v=ve;            v[j]+=v[i];            swap(v[i],v[sz-1]);            v.pop_back();            sort(v.begin(),v.end());            ans+=1.0*ve[i]*ve[j]/(all-p)*dp(v);        }    return mp[ve]=ans;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) fa[i]=i,sz[i]=1;    for (int i=1;i<=m;i++){        scanf("%d%d",&x,&y);        x=get(x); y=get(y);        if (x!=y) fa[x]=y,sz[y]+=sz[x];    }    for (int i=1;i<=n;i++)        if (i==fa[i]) ve.push_back(sz[i]);    sort(ve.begin(),ve.end());    all=n*(n-1)/2;    printf("%.6lf\n",dp(ve));}