首先总结一下思路,要从起点所在已经遍历的联通分量出发,到达为遍历的联通分量(记为共k个点),
需时间为 平均需要时间为n-1/k ,因为一次出发走到未被联通点的概率为k/(n-1);
然后就可成功转移到其他状态,而不会出现环。
把每个联通分量都抽象为一个点,每个的人数等于所在联通分量的人数。
但是直接用map 存状态,并未改变状态上限 (2^30) ,如 若有 30 1 2 3 这样的数据,直接超时,但uva这题并未卡,所以并未真正解决。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <set>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef unsigned long long LLU;
const int maxn = 35;
map<int,double> d;
int p[maxn],n,m,vis[maxn],k;
vector<int> G[maxn];
double dp(int s,int have){
if(d.count(s)) return d[s];
if(have == n) return d[s] = 0;
d[s] = (n-1)*1.0/(n-have);
for(int i=0;i<k;i++)if(!(s&(1<<i))){
d[s]+=dp(s|(1<<i),have+p[i])*(p[i]*1.0/(n-have));
}
return d[s];
}
int dfs(int u){
vis[u] = 1;
int cnt = 1;
for(int i=0;i<G[u].size();i++) if(!vis[G[u][i]]){
cnt+=dfs(G[u][i]);
}
return cnt;
}
int main()
{
int kase =1;
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) {
G[i].clear();
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
memset(vis,0,sizeof(vis));
k = 0;
for(int i=1;i<=n;i++){
if(!vis[i]){
p[k++]=dfs(i);
}
}
d.clear();
printf("Case %d: %.7lf\n",kase++,dp(1,p[0]));
}
return 0;
}