由于是树,所以两点之间只有一条路径,那么只要把每一条边砍断,再根据左右节点计算一下就好了
具体计算方法:假设这条砍掉的边就是full路,那么可以得到一个简单的性质,从这条路的左边到右边或者从右边到左右都一定会经过这条路,每一个点到除了自己以外其他点的概率就是p=1/(n-1).那么就可以转化为ans+=(当前情况的概率)*1.0也就是一条full路,到时候枚举边就可以得到总期望值了。期望值到底怎么算呢?如果从左到右来看,可以把左边所有家庭压缩到一个点,然后
P左−>右=(p∗右边一共的点数)(左边一共的家庭数)
右到左同理
P右−>左=(p∗左边一共的点数)(右边一共的家庭数)
然后ans+= P左−>右 * P右−>左
#define M 55
class FoxAndTouristFamilies {
public:
int cnt[M],dp[M],size[M];
vector<int>st[M];
bool mark[M][M];
void dfs(int x,int pre){
int &nw1=dp[x];
int &nw2=size[x];
nw1=cnt[x];
nw2=1;
for(int i=0;i<st[x].size();i++){
int to=st[x][i];
if(to==pre)continue;
dfs(to,x);
nw1+=dp[to];
nw2+=size[to];
}
}
double expectedLength(vector <int> A, vector <int> B, vector <int> f) {
int n=A.size()+1;
int m=f.size();
double ans=0;
double p=1.0/(n-1);
memset(dp,0,sizeof(dp));
memset(cnt,0,sizeof(cnt));
memset(size,0,sizeof(size));
memset(mark,0,sizeof(mark));
for(int i=0;i<n;i++)st[i].clear();
for(int i=0;i<n-1;i++){
int x=A[i];
int y=B[i];
st[x].push_back(y);
st[y].push_back(x);
}
for(int i=0;i<m;i++)cnt[f[i]]++;
dfs(0,-1);
for(int i=0;i<n;i++){
for(int j=0;j<st[i].size();j++){
int to=st[i][j];
if(mark[i][to]||mark[to][i])continue;
mark[i][to]=mark[to][i]=1;
int cntL1=m-dp[to];
int cntR1=size[to];
int cntL2=dp[to];
int cntR2=n-size[to];
double p1=pow(1.0*p*cntR1,cntL1);
double p2=pow(1.0*p*cntR2,cntL2);
if(!p1)p1=1.0;
if(!p2)p2=1.0;
ans+=p1*p2;
}
}
return ans;
}
};