Interconnect - POJ 3156 期望+状压dp

来源:互联网 发布:wampserver域名重定向 编辑:程序博客网 时间:2024/04/28 08:18

Interconnect
Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 1107 Accepted: 380 Special Judge

Description

There are two serious problems in the Kingdom of Lipshire: the roads and the fools who build them. Once upon a time, the King of Lipshire has decided to improve the road system because some roads became completely impassable — it was easier to travel cross-country instead of using those roads.

By King’s decree, new roads are to be built in Lipshire. Of course, the new road system must interconnect all towns, i. e. there must be a path connecting any two towns of Lipshire.

The road administration of Lipshire has resources to build exactly one road per year. Unfortunately, the fools who build these roads are completely out of control. So, regardless of the orders given, the fools randomly select two different towns a and b and build a road between them, even when those towns are already connected by a road. All possible choices are equiprobable. The road is build in such a manner that the only points where a traveler can leave it are the towns connected by this road. The only good thing is that all roads are bidirectional.

The King knows about the problem, but he cannot do anything about it. The only thing King needs to know is the expected number of years to wait before the road system of Lipshire becomes interconnected. He asked you to provide this information.

Input

The first line of the input contains two integers n and m (2 ≤ n ≤ 30, 0 ≤ m ≤ 1 000) — the number of towns in Lipshire, and the number of roads which are still good. The following m lines describe roads, one per line. Each road is described with two endpoints — two integer numbers ui and vi (1 ≤ uivi ≤ nui ≠ vi). There can be multiple roads between two towns, but the road from a town to itself is not allowed.

Output

Output the expected number of years to wait for the interconnected road system. If the system is already interconnected, output zero as an answer. Output the number with at least six precise digits after the decimal point.

Sample Input

sample input #12 11 2sample input #24 21 23 4

Sample Output

sample output #10.0sample output #21.5

题意:给你一些点和边,每次随机让其中两个点相连,问你使得所有的点连通,增加的边的期望是多少。

思路:num[i]表示恰好有i个点连通的区域有多少个,S状压这种情况,S2表示让其中某些区域相连后的状压情况dp[S]=(k1*dp[S2_1]+k2*dp[S2_2]...+k3*dp[S])/[n*(n-1)/2]+1.这是基本的转移方程,n*(n-1)/2为一共有多少种连接方式,k表示达到S2的有几种连接方式。

           另外我的代码在vj上交了之后跑出了141ms,目前直接上了第一的位置,【虽然拿自己的号只跑出了157ms

AC代码如下:

#include<cstdio>#include<cstring>#include<map>using namespace std;typedef unsigned long long ll;struct node{    int num[35];    double p;}box[10010];map<ll,int> match;int n,n2,m,p[40],sum[40],num;ll Hash[40],MOD=1e9+7;int find(int x){    return p[x]==x ? p[x] : p[x]=find(p[x]);}void Union(int u,int v){    u=find(u);    v=find(v);    if(u!=v)    {        p[u]=v;        sum[v]+=sum[u];    }}void debug(int pos){    for(int i=1;i<=5;i++)       printf("%d ",box[pos].num[i]);    printf("\n");}double solve(ll S){    int pos=match[S],i,j,k,temp=0;    ll S2;    double ret=0;    if(box[pos].num[0]==1)      return box[pos].p;    box[pos].num[0]=1;    if(S==Hash[n])    {        box[pos].p=0;        return 0;    }    for(i=1;i<=n;i++)    if(box[pos].num[i]>0)      for(j=i+1;j<=n;j++)         if(box[pos].num[j]>0)          {              S2=S-Hash[i]-Hash[j]+Hash[i+j];              if(match[S2]==0)              {                  num++;                  match[S2]=num;                  for(k=1;k<=n;k++)                     box[num].num[k]=box[pos].num[k];                  box[num].num[i]--;                  box[num].num[j]--;                  box[num].num[i+j]++;              }              k=box[pos].num[i]*i*box[pos].num[j]*j;              ret+=k*solve(S2);              temp+=k;          }    for(i=1;i<=n;i++)       if(box[pos].num[i]>=2)       {           S2=S-2*Hash[i]+Hash[i*2];           if(match[S2]==0)           {               num++;               match[S2]=num;               for(k=1;k<=n;k++)                  box[num].num[k]=box[pos].num[k];               box[num].num[i]-=2;               box[num].num[i*2]++;           }           j=box[pos].num[i]*i;           k=j*(j-1)/2-i*(i-1)/2*box[pos].num[i];           ret+=k*solve(S2);           temp+=k;       }    box[pos].p=(ret+n2)/temp;    return box[pos].p;}int main(){    int i,j,k,u,v;    ll S;    Hash[0]=1;    for(i=1;i<=30;i++)       Hash[i]=Hash[i-1]*MOD;    scanf("%d%d",&n,&m);    n2=n*(n-1)/2;    for(i=1;i<=n;i++)    {        p[i]=i;        sum[i]=1;    }    for(i=1;i<=m;i++)    {        scanf("%d%d",&u,&v);        Union(u,v);    }    for(i=1;i<=n;i++)       if(p[i]==i)         box[1].num[sum[i]]++;    S=0;    for(i=1;i<=n;i++)       S+=(ll)box[1].num[i]*Hash[i];    match[S]=1;num=1;    printf("%.6f\n",solve(S));}




0 0
原创粉丝点击