[关闭]
@Acqua 2019-02-26T09:03:23.000000Z 字数 1414 阅读 934

HDU6446 Tree and Permutation(Feb. 23th, 2019) 树形DP

动态规划

题目来源

题意

给定一棵有个结点的树,每条边有边权。记树上任意两点间最短路长度为,排列得到的权值就是。求按照每种全排列顺序在点之间走最短路得到的权值总和。(多组数据)

原理

个数的全排列数量为个。
如果把任意相邻两个数看作一个数,那么其余个数加上就有个数,全排列数就有个。
也就是说,对于个数中任意两个数,在个数的全排列中有种全排列满足这两个数相邻(要求顺序固定为)。
再把颠倒过来变成,那么个数的全排列中,个数中任意两个数都会出现次相邻。
问题转化为计算每两点之间最短路长,计算每条边的贡献即可。
初始化:
算法:对于每条边,贡献为

反思

  1. 程序辅助找规律(打表算法)。
  2. 半小时查标法则得到验证,效果显著。

代码

  1. // La Pluie
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<algorithm>
  6. using namespace std;
  7. typedef long long ln;
  8. const int N = 1e5 + 5, mod = 1e9 + 7;
  9. struct edge{
  10. int v; long long w; int next;
  11. } e[N << 1];
  12. int head[N], k;
  13. ln f[N] = {1}, size[N], ans, n;
  14. void adde(int u, int v, int w){
  15. e[k] = (edge){v, w, head[u]};
  16. head[u] = k++;
  17. }
  18. void dfs(int u, int f){
  19. size[u] = 1;
  20. for(int i = head[u]; i != -1; i = e[i]. next){
  21. int v = e[i]. v; ln w = e[i]. w;
  22. if(v == f) continue;
  23. dfs(v, u);
  24. ans = (ans + size[v] * (n - size[v]) % mod * w % mod) % mod;
  25. size[u] += size[v];
  26. }
  27. }
  28. int main(){
  29. for(int i = 1; i <= 100000; i++) f[i] = f[i - 1] * i % mod;
  30. while(~scanf("%lld", &n)){
  31. memset(head, -1, sizeof(head));
  32. k = 1, ans = 0;
  33. for(int i = 1; i < n; i++){
  34. int u, v; ln w;
  35. scanf("%d %d %lld", &u, &v, &w);
  36. adde(u, v, w); adde(v, u, w);
  37. }
  38. dfs(1, 0);
  39. printf("%lld\n", ans * f[n - 1] % mod * 2 % mod);
  40. }
  41. return 0;
  42. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注