借鉴了一位大佬的博客:https://blog.csdn.net/qq_36300700/article/details/82108535
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6446
题意:给出一颗树,按节点进行全排列,给你一棵树,以全排列的第一个树为根节点,求出根节点到其他点的最短路径之和,把这些和在相加,求最后结果。
分析:对于任意两个点之间的距离都经过了 2*(n-1)!次,用dp算出这棵树上任意两点的最短距离之后乘上次数就是最后结果。
dp算出任意两点的最短距离参考这篇博客:https://blog.csdn.net/rain722/article/details/75633721
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <map>
#include <queue>
#include <vector>
using namespace std;
#define ll long long
const int maxn =100000+10;
const ll mod=1e9+7;
int N,head[maxn],k;
ll f[maxn],dp[maxn],sum[maxn];
struct Edge
{
int v,next;
ll w;
Edge(){};
Edge(int v1, ll w1, int next1)
{
v=v1,w=w1,next=next1;
}
}e[maxn*2];
void add_edge(int u,int v,ll w)
{
e[k]=Edge(v,w,head[u]);
head[u]=k++;
e[k]=Edge(u,w,head[v]);
head[v]=k++;
}
void dfs(int u,int fa)
{
sum[u]=1;
for(int i=head[u]; i!=-1; i=e[i].next)
{
int v= e[i].v;
ll w=e[i].w;
if(fa==v)
continue;
dfs(v,u);
sum[u]+=sum[v];
dp[u]=(dp[u]+dp[v])%mod;
dp[u]=(dp[u]+w*sum[v]%mod*(N-sum[v])%mod)%mod;
}
}
int main()
{
f[1]=1;
for(ll i=2; i<=100000; i++)
{
f[i]=f[i-1]*i%mod;
}
while(scanf("%d",&N)!=EOF)
{
k=0;
memset(head,-1,sizeof(head));
int a,b;
ll c;
for(int i=0; i<N-1; i++)
{
scanf("%d %d %lld",&a,&b,&c);
add_edge(a,b,c);
}
memset(dp,0,sizeof(dp));
dfs(1,-1);
dp[1]=dp[1]*f[N-1]%mod;
printf("%lld\n",2*dp[1]%mod);
}
return 0;
}