zoukankan      html  css  js  c++  java
  • 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 }
     
  • 相关阅读:
    敏捷转型——团队如何变敏捷?
    什么是敏捷方法论
    禅道项目管理软件会有夜间模式吗?
    程序员如何避免“代码被猫吃了”?
    项目经理:我太难了!
    python进阶(4)--字典
    python进阶(3)--条件判断、用户输入
    python进阶(2)--列表
    python进阶(1)--变量与数据类型、python之禅
    java进阶(42)--注解
  • 原文地址:https://www.cnblogs.com/usedrosee/p/4187863.html
Copyright © 2011-2022 走看看