HDU6446 Tree and Permutation(树上DP)

传送门:点我

Tree and Permutation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2191    Accepted Submission(s): 826

Problem Description
There are N vertices connected by N1 edges, each edge has its own length.
The set { 1,2,3,,N } contains a total of N! unique permutations, let’s say the i-th permutation is Pi and Pi,j is its j-th number.
For the i-th permutation, it can be a traverse sequence of the tree with N vertices, which means we can go from the Pi,1-th vertex to the Pi,2-th vertex by the shortest path, then go to the Pi,3-th vertex ( also by the shortest path ) , and so on. Finally we’ll reach the Pi,N-th vertex, let’s define the total distance of this route as D(Pi) , so please calculate the sum of D(Pi) for all N! permutations.
 
Input
There are 10 test cases at most.
The first line of each test case contains one integer N ( 1N105 ) .
For the next N1 lines, each line contains three integer XY and L, which means there is an edge between X-th vertex and Y-th of length L ( 1X,YN,1L10^9 ) .
 Output
For each test case, print the answer module 109+7 in one line.
 Sample Input
3
1 2 1
2 3 1
3
1 2 1
1 3 2
Sample Output
16
24
 
 
 
  • 题目大意:
         第一行给定n,表示n个顶点,后面n-1行代表边的两个端点和边的权值。
         要输出的是n个顶点全排列对所有情况,按点依次访问的时候,经过的权值和。
         比如说样例1:
         三个顶点,即对1,2,3全排列,共有6种方式。(1->2->3,1->3->2.......)
         按每种情况的访问点的顺序累加权值。
  • 思路:
         这题考虑的是每条边对答案的贡献。
         考虑顶点有n个的情况:
         假设顶点x和顶点y有边相连,那么在全排列中这条边会被访问几次?
  •  固定x,对其余所有顶点进行全排列,得到(n-1)!种情况。
  • 固定y,对其余所有顶点进行全排列,得到(n-1)!种情况。
         显而易见,每条边在全排列中贡献了2*(n-1)!次,再乘上每2个点的最小路径dis[x][y],就是每条边对答案的贡献,即2*(n-1)!*dis[x][y]
         任意两点距离最短路径参考HDU5723  HDU2376
代码:
#include<bits/stdc++.h>
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define mst(a, b)    memset(a, b, sizeof a)
#define REP(i, x, n)    for(int i = x; i <= n; ++i)
#define pi acos(-1.0)
#define Max_N 1001
#define  inf 0x3f3f3f3f      
using namespace std;
const LL mod = 1e9+7;
LL dp[100005];
int sum[100005];
int n;
vector<pair<int,LL> >v[100005];
LL f[100005];
void dfs(int now,int father){
    sum[now] = 1;
    for(int i = 0 ; i < v[now].size() ;  i++){
        int son = v[now][i].first;
        LL  len = v[now][i].second;
        if(son == father)continue;
        dfs(son,now);
        sum[now] += sum[son];
        dp[now]  += (dp[son]+((n-sum[son])%mod*sum[son])%mod*len%mod*2LL*f[n-1]%mod)%mod;
        dp[now] = (dp[now]+mod)%mod;
    }
}
int main()
{
    f[0]=0 ; f[1] = 1;
    for(int i = 2 ; i <= 100000; i ++){
        f[i]=(f[i-1]*i)%mod;
    }
    while(~scanf("%d",&n)){
        memset(dp,0,sizeof(dp));
        memset(sum,0,sizeof(sum));
        for(int i = 0 ; i <= n ; i++)v[i].clear();
        for(int i = 0 ; i < n-1; i ++){
            int x,y;
            LL w;
            scanf("%d %d %lld",&x,&y,&w);
            v[x].push_back(make_pair(y,w));
            v[y].push_back(make_pair(x,w));
        }
        dfs(1,-1);
        printf("%lld
",dp[1]);
    }
}
/*
3
1 2 1
2 3 1
3
1 2 1
1 3 2
*/
原文地址:https://www.cnblogs.com/Esquecer/p/10477477.html