题意:给出一颗树,按节点进行全排列,给你一棵树,以全排列的第一个树为根节点,求出根节点到其他点的最短路径之和,把这些和在相加,求最后结果
分析:整体思路是先建立领接表,然后计算各边的权重,乘以各边的权值,然后乘以(n-1)!再乘以2。
问题就是这个权重怎么算,假设有一棵树,将其中的一条边砍断,这课树就分为两部分,部分1的每个结点,都需要经过这条边,到另外一个部分2的所有结点上走一遍,所以这条边的权重就可以理解为,部分1的结点数之和i乘以部分2的结点数之和j。
知道了计算权重的方法之后,就很好计算了,先建立一颗以1为根部的树,然后通过dfs遍历整棵树,遇到叶子返回1,父节点等于他的所有子节点之和再加1,于是每个结点就都有了一个数字,代表着他及他之下所有子节点数的和。用一个数组a存放即可。如果将一棵树分成两部分之后,小的那部分的结点数之和就等于他的根部结点a[i]的数字。大的那部分的结点数就等于a[1]-a[i]。然后进行计算即可。
代码撸一遍很快,改错改了几个小时。
WA了十几次,总结起来其实只有三个错误
1. 一开始忘了题目需要mod 1e9+7了,这个错误很快就发现了。
2. 在算好权重之后,还需要遍历一遍整棵树,这个遍历方法出了问题,因为在构建树的时候,每条路径是双向的,遍历的时候每条路径都遍历了两边。一开始是加了一个简单的条件限制遍历已经走过的路,但是数据量稍微大一点就出错了。找这个错误很简单,随便造了几组数据就发现错误了。在修改的时候,一开始一直想着加更多的限制条件,但这很明显不对,因为数据变得更大就又会出错。后来想到了,既然每条路径都遍历了两次,那么直接把权重和sum除以2就行了。这个方法是对的。
3. 权重和在累加的过程中需要有可能会超过longlong的上限,需要一边加,一边mod。这个问题找了我至少4个小时,因为在修改了上面两个错误之后,百分之99的数据都可以过了,我自己造了七八组数据,都没有问题,然后就不知道怎么办了。在寻找过程中,我有一次有想到这个问题,但是因为sum先mod再除以2会还是有问题(比如sum mod之后等于1,除以2就直接等于0了),交上去还是WA,就没有往这个方面去想了,导致后来做了几个小时的无用功。其实只需要先mod,不需要除以2,因为后面在和阶乘相乘的时候也要乘以2,就可以抵消了。
这三个问题解决了,再提交就AC了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100005;
const int mod=1e9+7;
ll jc[maxn];
vector<pair<ll,ll> >vis[maxn];
ll qz[maxn];
ll sum=0;
ll fl[maxn];
ll n;
void jjc()
{
for(int i=2;i<=(n-1);i++)
{
sum*=i;
if(sum>mod)sum%=mod;
}
sum%=mod;
}
void dfs(int i)
{
memset(qz,0,sizeof qz);
memset(fl,0,sizeof fl);
sum=0;
stack<int >s;
s.push(i);
fl[i]=1;
while(!s.empty())
{
int flag=0;
ll now=s.top();
for(int i=0;i<vis[now].size();i++)
{
ll v=vis[now][i].first;
if(fl[v]==1)
continue;
flag=1;
fl[v]=1;
s.push(v);
}
if(flag==0)
{
s.pop();
for(int i=0;i<vis[now].size();i++)
{
ll v=vis[now][i].first;
qz[now]+=qz[v];
}
qz[now]++;
}
}
}
int main()
{
while(cin>>n)
{
memset(vis,0,sizeof vis);
for(int i=0;i<n-1;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
vis[a].push_back(make_pair(b,c));
vis[b].push_back(make_pair(a,c));
}
dfs(1);
for(int i=1;i<=n;i++)
{
for(int j=0;j<vis[i].size();j++)
{
ll v=vis[i][j].first;
ll minn=min(qz[i],qz[v]);
ll k=(qz[1]-minn)*minn;
sum+=(k*vis[i][j].second);
}
sum%=mod;
}
jjc();
cout<<sum<<endl;
}
}