HDU 6446 Tree and Permutation (dp)

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

分析:对于每一条边都经过了 2*(n-1)!次,用dp算出这棵树上任意两点的最短距离之后乘上次数就是最后结果。

例如:

1 2 3 4  这几个数,若以1为根节点,那么有下列排列

1 2 3 4

1 2 4 3

1 3 2 4

1 3 4 2

1 4 2 3

1 4 3 2

可以看出点1到任意点都经过了(4-1)!次,由于是双向的还得乘2。

对于dp算出任意两点的最短距离,可参考这篇博客:https://blog.csdn.net/rain722/article/details/75633721

代码:

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define lowbit(x) (x&(-x))
#define mem(a,b) memset(a,b,sizeof(a))
#define FRER() freopen("in.txt","r",stdin);
#define FREW() freopen("out.txt","w",stdout);

using namespace std;

typedef pair<int,int> pii;
const int maxn = 200000 + 7 , inf = 0x3f3f3f3f ;

int nxt[maxn],to[maxn],head[maxn];
ll cap[maxn],d[maxn],siz[maxn];
int n,nEdge;
void addEdge(int u,int v,ll c){
    nxt[nEdge]=head[u],to[nEdge]=v,cap[nEdge]=c,head[u]=nEdge++;
}

void dp(int u,int fa){
    d[u] = 0 , siz[u] = 1;
    for(int e = head[u];~e;e=nxt[e]){
        int v = to[e];
        if(v==fa) continue;
        dp(v,u);
    }
    for(int e = head[u];~e;e=nxt[e]){
        int v = to[e];
        if(v==fa) continue;
        siz[u]+=siz[v];
        d[u]=(d[u]+d[v])%mod;
        d[u]=(d[u]+cap[e]*siz[v]%mod*(n-siz[v])%mod)%mod;
    }
}

int main(){
    //FRER();
    //FREW();
    int u,v;
    ll c;
    while(~scanf("%d",&n)){
        mem(head,-1);
        nEdge = 0;
        for(int i=0;i<n-1;i++){
            scanf("%d%d%lld",&u,&v,&c);
            addEdge(u,v,c);
            addEdge(v,u,c);
        }
        dp(1,0);
        ll f = 1;
        for(ll i = 1 ; i <= n-1 ;i++)
            f = f * i % mod;
        ll ans = d[1] * f %mod;
        ans = ans * 2 %mod;
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Insist_77/article/details/82054424
今日推荐