题目在此。
思考暴搜,好像不行,我们来退一步想。
树上的我肯定是会的。
用down[x]表示x这个节点往下走的期望路径长度。
其中表示x的儿子,表示x的儿子个数,表示x到i的边长。
用up[x]表示这个节点往上走的期望路径长度。
是不是眼花缭乱。其中是父亲的度(连边就算)。(特殊讨论tot[fa]=1)
其实很好理解,从x的外部节点走向x是不是一定要经过fa到x的这条边,所以我们加在外面,另外的,我们算出fa向上走的期望长度乘向上走的路的条数,加上fa向下走的期望长度乘上 向下走的路的条数(加起来相当于从fa向每个方向走的长度乘方向总数)再减去这个子树带来的影响,最后除以剩下往外走的路径条数。
有点难理解吧,这里感性一点。
如果有一个环呢?
就变成了基环树。找环我肯定也是会的。处理出每一个节点的down我也是会的。(相当于很多棵树)
关键是up,怎么处理一个节点往外走的期望路径长度。
显然对于每一棵小树我们只需要根节点往外走的期望就足够了。
怎么求根节点往外走的期望长度?
分两种情况讨论:
1.顺时针走。
2.逆时针走。
明显向两边走的几率都是二分之一。
假设当前点是x,要往外走,那么up[x]=(down[环上的另一个节点]+x到这个节点的距离)*x到这个节点概率。
第一个文字可以枚举,第二个文字可以累加路径,第三个文字“概率”应该怎么求呢?
我们经过一个环上节点p之后,继续往下走的几率是。因为其他的几率都分给了这棵树。
特殊讨论顺时针或逆时针的最后一个节点,因为到了这个节点,就不能再往下走了,所有的几率都分给了这一棵树。这题荒废了我1个半小时做和40分钟写博客。
#include
#include
#include
#include
#define ne (now==t?1:now+1)
#define la (now==1?t:now-1)
using namespace std;
int n,m;
struct edge{
int y,next,c;
}s[200010];
int first[100010],len=0;
bool vis[100010],we=false,tf=false,stack[100010];
bool inlp[100010];
double down[100010],up[100010];
int son[100010];
int loop[100010],tot[100010],dis[100010],t=0;
void ins(int x,int y,int c){
len++;
s[len]=(edge){y,first[x],c};first[x]=len;
}
void dfs_1(int x,int fa){
down[x]=0;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
tot[x]++;
if(y==fa || inlp[y]) continue;
dfs_1(y,x);
down[x]+=down[y]+s[i].c;son[x]++;
}
if(son[x]!=0) down[x]/=son[x];
}
void dfs_2(int x,int fa){
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(y==fa || inlp[y]) continue;
up[y]=s[i].c+((tot[x]-son[x])*up[x]+down[x]*son[x]-down[y]-s[i].c)/(tot[x]-1==0?1:tot[x]-1);
dfs_2(y,x);
}
}
void find_loop(int x,int fa){
stack[x]=true;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(y==fa) continue;
if(stack[y]){
we=tf=true;
loop[++t]=y;
inlp[y]=true;
}
if(!we) find_loop(y,x);
if(tf){
if(loop[1]!=x) loop[++t]=x,inlp[x]=true,dis[t]=s[i].c;
else tf=false,dis[1]=s[i].c;
break;
}
if(we) break;
}
stack[x]=false;
}
int main(){
scanf("%d %d",&n,&m);
int x,y,c;
for(int i=1;i<=m;i++){
scanf("%d %d %d",&x,&y,&c);
ins(x,y,c);
ins(y,x,c);
}
if(m==n-1) dfs_1(1,0),dfs_2(1,0);
else{
find_loop(1,0);
for(int i=1;i<=t;i++) dfs_1(loop[i],0);
for(int i=1;i<=t;i++){
//逆时针
double to,di=1.0/2;
int now=i==t?1:i+1;
to=dis[now];
while(now!=i){
di/=(son[loop[now]]+1);
up[loop[i]]+=(to+down[loop[now]])*di*(ne==i?son[loop[now]]+1:son[loop[now]]);
now=ne;
to+=dis[now];
}
//顺时针
di=1.0/2;
now=i==1?t:i-1;
to=dis[i];
while(now!=i){
di/=(son[loop[now]]+1);
up[loop[i]]+=(to+down[loop[now]])*di*(la==i?son[loop[now]]+1:son[loop[now]]);
to+=dis[now];
now=la;
}
}
for(int i=1;i<=t;i++) dfs_2(loop[i],0);
}
double ans=0;
for(int i=1;i<=n;i++) ans+=((tot[i]-son[i])*up[i]+son[i]*down[i])/tot[i];
printf("%.6lf",ans/n);
}