#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 7;
struct node{
int ne,to;
double w;
}a[MAXN << 1];
map<int,double> mp[MAXN];
int head[MAXN],cnt = 0;
int loop[25],vis[MAXN],tot,id,fa[MAXN];
double E[MAXN];
void add(int x,int y,double w){
a[++cnt].ne = head[x];
head[x] = cnt;
a[cnt].to = y;
a[cnt].w = w;
}
void get_cir(int x,int f){
vis[x] = ++id;
for(int i = head[x];i;i = a[i].ne){
int y = a[i].to;
if(y == f) continue;
if(vis[y]){
if(vis[y] < vis[x]) continue;
loop[++tot] = y;
for(;y != x;y = fa[y])
loop[++tot] = fa[y];
}
else fa[y] = x,get_cir(y,x);
}
}
double dp[MAXN];
int son[MAXN],deg[MAXN];
vector<int> tmp;
int root;
void dfs(int x,int fa){//正常求给定根的期望
son[x] = 0;
dp[x] = 0;
for(int i = head[x];i;i = a[i].ne){
int y = a[i].to;
if(y == fa || vis[y]) continue;
// tmp.push_back(y);
dfs(y,x);
E[x] += (dp[y] + a[i].w);
son[x] += 1;
}
if(son[x] != 0)
dp[x] = E[x] / (son[x]);
if(x != root) son[x] += 1;
}
void clear(){
for(int i = 0;i < tmp.size();++i) vis[tmp[i]] = 0;
tmp.clear();
}
void go(int x,int fa){//换根
for(int i = head[x];i;i = a[i].ne){
int y = a[i].to;
if(y == fa || vis[y])continue;
double w = a[i].w;
int k = deg[x] - 1;
if(!k) k += 1;
// dp[y] = ((dp[x] * deg[x] - dp[y] - w) / k + w) / deg[y] + \
// (dp[y] * (deg[y] - 1) / deg[y]);
E[y] += (E[x] - dp[y] - w) / max(1,son[x] - 1) + w;
go(y,x);
}
}
double g[MAXN],f[MAXN];
void get(int x,int fa){//统计环上的期望
bool has_son = 0;
g[x] = 0;
for(int i = head[x];i;i = a[i].ne){
int y = a[i].to;
if(y == fa || !vis[y] || y == root) continue;//必须得是环上的
has_son = 1;
get(y,x);
g[x] += g[y] + a[i].w;
}
if(x == root) return ;
int k = son[x];if(!k) k += 1;
if(!has_son) g[x] = E[x] / k;
else k = son[x] + 1,g[x] = (E[x] + g[x]) / k;
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i = 1;i <= m;++i){
int x,y;
double w;
scanf("%d %d %lf",&x,&y,&w);
add(x,y,w);
add(y,x,w);
deg[x] += 1,deg[y] += 1,mp[x][y] = mp[y][x] = w;
}
get_cir(1,-1);
for(int i = 1;i <= n;++i) vis[i] = 0;
for(int i = 1;i <= tot;++i) vis[loop[i]] = 1;
if(tot == 0){
root = 1;
dfs(1,-1);
go(1,-1);
for(int i = 1;i <= n;++i) dp[i] = E[i] / deg[i];
double ans = 0;
for(int i = 1;i <= n;++i) ans += dp[i];
ans /= n;
printf("%.5f\n",ans);
return 0;
}
for(int i = 1;i <= tot;++i){
root = loop[i];
dfs(loop[i],-1);//统计子环上子树信息
// clear();
}
// for(int i = 1;i <= n;++i) f[i] = dp[i];
//统计环上期望
for(int i = 1;i <= tot;++i){
root = loop[i];
get(loop[i],-1);
f[loop[i]] = g[loop[i]];
}
for(int i = 1;i <= tot;++i)
E[loop[i]] += f[loop[i]],son[loop[i]] += 2;
//现在开始统计各个子树信息
//换根DP
for(int i = 1;i <= tot;++i)go(loop[i],-1);
for(int i = 1;i <= n;++i)dp[i] = E[i] / deg[i];
double ans = 0;
for(int i = 1;i <= n;++i)ans += dp[i];
ans /= n;
printf("%.5f\n",ans);
}
P2081 [NOI2012] 迷失游乐园
最新推荐文章于 2024-07-25 11:27:31 发布