一开始直接用set做状态,并且用map做记忆,直接超时。
后来改成用hash值做记忆,每个点的查找时间,基本在30左右。
每个状态的定义为 一个 30的数组,存的是当前联通分量中元素个数为i的个数。
状态转移,只有同时选同一集合内元素会导致无法转移到下一阶段。
先计算平均需多少天转移到的联通分量总数 减1的状态,然后具体计算转移到每个下一个状态需要的时间。
如果 当前选择不同联通分量的概率为 x/y 那么,需天数为 y/x。
再往下。分开计算每种转移情况,由于这样做并不是指定某两个联通分量联合,而是某两类l联通分量联合,所以,当都取用一类联合时要乘 A(2,该联通分量总数 )。
不同时,要乘上两个不同联通分量总数相乘再乘以2.
#include <cmath>
#include <map>
#include <set>
#include <deque>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
#define rep1(i,n) for(int (i)=1;(i)<=(n);(i)++)
const int maxn = 31;
struct node{
int a[maxn];
double res;
bool operator==(const node& b)const{
for(int i=1;i<=30;i++){
if(a[i]!=b.a[i]) return 0;
}
return 1;
}
};
vector<int> G[maxn];
int n,m;
int read(){
if(scanf("%d %d",&n,&m)!=2) return 0;
rep1(i,n)G[i].clear();
rep(i,m){
int x,y;
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
return 1;
}
int vis[maxn],b[maxn],cnt;
int dfs(int u){
vis[u] = 1;
int res = 1;
for(int i=0;i<G[u].size();i++){
if(!vis[G[u][i]])
res+=dfs(G[u][i]);
}
return res;
}
const int maxhash = 1000007;
int head[maxhash],next[maxhash*3];
vector<node> st;
int hash(node& A){
int res = 0;
rep1(i,30){
res=(res*30+A.a[i])%maxhash;
}
return res;
}
int ok ;
int Vis(node& A){
int id = hash(A);
for(int p =head[id];p!=-1;p=next[p]){
if(st[p] == A){
ok = 1; return p;
}
}
st.push_back(A);
int u = st.size()-1;
next[u] = head[id];
head[id] = u;
return u;
}
double dp(node& A){
ok = 0; int id = Vis(A);
if(ok) return st[id].res;
if(A.a[n] == 1){
return st[id].res = 0;
}
int sum = n*(n-1);
double ans = 0;
rep1(i,30)if(A.a[i]){
sum-=A.a[i]*i*(i-1);
}
ans =(n*(n-1)*1.0)/(sum);
rep1(i,30)if(A.a[i]){
for(int j=i;j<=30;j++)if(A.a[j]){
if(i == j && A.a[j] < 2) continue;
int ji = (A.a[i])*(A.a[j])*2.0;
if(i == j) ji = (A.a[i])*(A.a[j]-1);
A.a[i]--; A.a[j]--; A.a[i+j]++;
ans+=dp(A)*(i*j*ji)/sum;
A.a[i]++; A.a[j]++; A.a[i+j]--;
}
}
return st[id].res = ans;
}
double solve(){
st.clear();
memset(head,-1,sizeof(head));
node A;
rep(i,31) A.a[i] = 0;
rep(i,cnt){
A.a[b[i]]++;
}
return dp(A);
}
int main()
{
while(read()){
memset(vis,0,sizeof(vis));
cnt = 0;
rep1(i,n){
if(!vis[i]){
b[cnt++] = dfs(i);
}
}
printf("%.10lf\n",solve());
}
}