题目大意
https://www.luogu.org/problemnew/show/CF235D
分析
我们先考虑它是树的情况
我们设$event(x,y)$表示删除点x是y与x联通这件事对答案贡献的期望
我们设x到y这一条链的长度为$len$,$x$和$y$所属联通块的大小为$n$
则我们可以猜测$event$的值为$frac{1}{len}$
我们可以用数学归纳法证明
我们知道直接选到$x$的概率为$frac{1}{n}$
先选到其它点再通过若干步选到x的概率为$frac{n-len}{n} * frac{1}{len}$
由此得证
于是我们在考虑它是基环树的情况
我们不难发现对于不经过环的路径没有影响
而其它路径我们把它不经过环的那些距离设为$x$,经过环的两条路分别为$y$和$z$
$event(x,y)$发生的概率实际上就是这两条路中$x$是任意一条路上第一个被删除的结点的概率
我们再容斥一下就可以得到$event(x,y) = frac{1}{x+y} + frac{1}{x+z} - frac{1}{x+y+z}$
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int n,m,dep[5000],id[5000],cnt,sum,acc[5000],lca[3020][3020],f[5000];
int dfn[5000],low[5000],ist[5000],belong[5000],tot[5000],maxid;
double Ans;
stack<int>a;
vector<int>v[5000];
inline void tarjan(int x,int fa){
dfn[x]=low[x]=++cnt;
a.push(x);
ist[x]=1;
for(int i=0;i<v[x].size();i++)
if(v[x][i]!=fa){
if(!dfn[v[x][i]]){
tarjan(v[x][i],x);
low[x]=min(low[x],low[v[x][i]]);
}else if(ist[v[x][i]]){
low[x]=min(low[x],dfn[v[x][i]]);
}
}
if(low[x]==dfn[x]){
sum++;
while(1){
int u=a.top();
a.pop();
ist[u]=0;
belong[u]=sum;
tot[sum]++;
if(u==x)break;
}
}
}
inline int sf(int x){return f[x]==x?x:f[x]=sf(f[x]);}
inline void work(int x,int ac,int fa){
acc[x]=ac;
f[x]=x;
for(int i=0;i<v[x].size();i++)
if(v[x][i]!=fa&&tot[belong[v[x][i]]]==1){
dep[v[x][i]]=dep[x]+1;
work(v[x][i],ac,x);
if(sf(v[x][i])!=sf(x))
f[sf(v[x][i])]=sf(x);
}
for(int i=1;i<=n;i++)
if(acc[i]==ac)lca[x][i]=lca[i][x]=sf(i);
}
inline void dfs(int x,int fa){
id[x]=id[fa]+1,dep[x]=1,acc[x]=x;
work(x,x,x);
for(int i=0;i<v[x].size();i++)
if(v[x][i]!=fa&&!id[v[x][i]]){
if(tot[belong[v[x][i]]]>1)dfs(v[x][i],x);
}
}
int main(){
int i,j,k,x,y;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
x++,y++;
v[x].push_back(y);
v[y].push_back(x);
}
for(i=1;i<=n;i++)
if(!dfn[i])tarjan(i,0);
for(i=1;i<=n;i++)
if(tot[belong[i]]>1){
id[i]=1;
maxid=tot[belong[i]];
dfs(i,0);
break;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
if(acc[i]==acc[j])Ans+=1.0/(dep[i]+dep[j]-2*dep[lca[i][j]]+1);
else {
int x=dep[i]+dep[j],y=abs(id[acc[i]]-id[acc[j]])-1,z=maxid-y-2;
Ans+=1.0/(x+y)+1.0/(x+z)-1.0/(x+y+z);
}
}
printf("%0.7lf
",Ans);
return 0;
}