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 }

 

 

你可能感兴趣的:(HDU)