hdu 6446 Tree and Permutation(dfs+思维)

题意:给出一颗树,按节点进行全排列,给你一棵树,以全排列的第一个树为根节点,求出根节点到其他点的最短路径之和,把这些和在相加,求最后结果

分析:整体思路是先建立领接表,然后计算各边的权重,乘以各边的权值,然后乘以(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;
    }
} 

猜你喜欢

转载自blog.csdn.net/qq_41564817/article/details/82082863
今日推荐