hdu 5148 cities 树形DP

*******************************bestcoder题解********************************
Cities 选出K个点v1,v2,...vK使得Ki=1Kj=1dis(vi,vj)最小. 考虑每条边的贡献,一条边会把树分成两部分,若在其中一部分里选择了x个点,则这条边被统计的次数为x*(K-x)*2. 那么考虑dp[u][i]表示在u的子树中选择了i个点的最小代价,有转移dp[u][i]=minKj=0(dp[u][ij]+dp[v][j]+j(Kj)2wu,v),式子中u为v的父亲,wu,v表示(u,v)这条边的长度. 时间复杂度O(nK^2).

****************************************************************************

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <memory.h>
  5 using namespace std;
  6 typedef long long LL;
  7 const int INF = 0x3fffffff;
  8 const LL LINF = INF * 1ll * INF;
  9 using namespace std;
 10 
 11 #define MAXN 5005
 12 
 13 struct Edge{
 14     int to;
 15     int w;
 16     int next;
 17 };
 18 
 19 LL dp[MAXN][60];       //dp[n][k]  代表第n个结点 有k个结点连通
 20 Edge e[MAXN];
 21 int head[MAXN];
 22 int t;
 23 int n,k;
 24 
 25 //适用于正负整数
 26 template <class T>
 27 inline bool scan_d(T &ret) {
 28    char c; int sgn;
 29    if(c=getchar(),c==EOF) return 0; //EOF
 30    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
 31    sgn=(c=='-')?-1:1;
 32    ret=(c=='-')?0:(c-'0');
 33    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
 34    ret*=sgn;
 35    return 1;
 36 }
 37 
 38 //取小值给ans
 39 LL update(LL &ans,LL temp)
 40 {
 41     if (ans > temp) ans = temp;
 42 }
 43 
 44 void dfs(int u,int fa){
 45     for(int i = head[u];~i;i = e[i].next){//注意~运算
 46         if(e[i].to == fa) continue;     //不再访问父亲结点
 47         dfs(e[i].to,u);
 48     }
 49     for(int i = 0;i <= k;i++) dp[u][i] = LINF;   //LINF代表不可达
 50     dp[u][1] = 0;
 51     for(int i = head[u];!i;i = e[i].next){       //访问当前点u的所有子树
 52         if(e[i].to == fa) continue;              //不包含父亲结点
 53         int v = e[i].to;
 54         for(int a = k;a >= 0;a--){              //类似01背包
 55             for(int b = 1;a+b <= k;b++){        //因为一条边把树分成两个部分,其中一部分已经访问了a个结点,则另一部分还需访问k-a个结点
 56                 if(dp[v][b] == LINF) break;     //若为LINF则不可达   比如,只有两个子节点,则dp[v][4]就不存在
 57                 update(dp[u][a+b],dp[u][a] + dp[v][b] + 2ll*b*(k-b)*e[i].w);
 58             }
 59         }
 60     }
 61 }
 62 
 63 //建立关于边的临街边
 64 void addedge(int from,int to,int w)
 65 {
 66     e[t].to = to;
 67     e[t].w = w;
 68     e[t].next = head[from];
 69     head[from] = t;
 70     t++;
 71 }
 72 
 73 
 74 void process()
 75 {
 76     int from,target,weight;
 77     scan_d(n);
 78     scan_d(k);
 79     t = 0;
 80     memset(head,-1,sizeof(head));
 81     for (int i = 1;i < n; ++ i) {
 82         scan_d(from);
 83         scan_d(target);
 84         scan_d(weight);
 85         addedge(from,target,weight);
 86         addedge(target,from,weight);
 87     }
 88     dfs(1,-1);
 89     LL ans = LINF;
 90     for (int i = 1;i <= n; ++ i) {
 91         update(ans,dp[i][k]);
 92     }
 93     cout << ans << endl;
 94 }
 95 
 96 
 97 int main()
 98 {
 99     int T;
100     cin >> T;
101     while (T--)
102     {
103         process();
104     }
105     return 0;
106 }
 
原文地址:https://www.cnblogs.com/usedrosee/p/4187863.html