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 N−1 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.
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 ( 1≤N≤105 ) .
For the next N−1 lines, each line contains three integer X, Y and L, which means there is an edge between X-th vertex and Y-th of length L ( 1≤X,Y≤N,1≤L≤10^9 ) .
The first line of each test case contains one integer N ( 1≤N≤105 ) .
For the next N−1 lines, each line contains three integer X, Y and L, which means there is an edge between X-th vertex and Y-th of length L ( 1≤X,Y≤N,1≤L≤10^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]
代码:
#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\n",dp[1]); } } /* 3 1 2 1 2 3 1 3 1 2 1 1 3 2 */