zoukankan      html  css  js  c++  java
  • BZOJ4987:Tree(树形DP)

    Description

    从前有棵树。
    找出K个点A1,A2,…,Ak。
    使得∑dis(AiAi+1),(1<=i<=K-1)最小。

    Input

    第一行两个正整数n,k,表示数的顶点数和需要选出的点个数。
    接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边。
    I<=k<=n。
    l<x,y<=n
    1<=z<=10^5
    n <= 3000

    Output

    一行一个整数,表示最小的距离和。

    Sample Input

    10 7
    1 2 35129
    2 3 42976
    3 4 24497
    2 5 83165
    1 6 4748
    5 7 38311
    4 8 70052
    3 9 3561
    8 10 80238

    Sample Output

    184524

    Solution

    贴一下神仙$beginend$的题解qwq
    显然最优情况一定是原树的一棵大小为k的连通子树,然后直径上的边系数是1,其余边的系数是2。
    那么我们可以进行树形dp,设f[i,j,0/1/2]表示以i为根的子树选了j个点,且直径的端点已经选了0/1/2个的最优方案。

    Code

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #define N (3009)
     5 using namespace std;
     6 
     7 struct Edge{int to,next,len;}edge[N<<1];
     8 int n,m,u,v,l,ans,INF,size[N],f[N][N][3],tmp[N][3];
     9 int head[N],num_edge;
    10 
    11 void add(int u,int v,int l)
    12 {
    13     edge[++num_edge].to=v;
    14     edge[num_edge].len=l;
    15     edge[num_edge].next=head[u];
    16     head[u]=num_edge;
    17 }
    18 
    19 void Min(int &x,int y){x=min(x,y);}
    20 
    21 void Dfs(int x,int fa)
    22 {
    23     size[x]=1;
    24     for (int i=0;i<=n;i++)
    25         for (int j=0;j<=2;j++)
    26             f[x][i][j]=INF;
    27     f[x][1][0]=f[x][1][1]=f[x][1][2]=0;
    28     for (int i=head[x]; i; i=edge[i].next)
    29         if (edge[i].to!=fa)
    30         {
    31             Dfs(edge[i].to,x);
    32             for (int j=0; j<=size[x]+size[edge[i].to]; ++j)
    33                 tmp[j][0]=tmp[j][1]=tmp[j][2]=INF;
    34             for (int j=0; j<=size[x]; ++j)
    35                 for (int k=0; k<=size[edge[i].to]; ++k)
    36                 {
    37                     int to=edge[i].to,len=edge[i].len;
    38                     Min(tmp[j+k][0],f[x][j][0]+f[to][k][0]+len*2);
    39                     Min(tmp[j+k][1],f[x][j][1]+f[to][k][0]+len*2);
    40                     Min(tmp[j+k][1],f[x][j][0]+f[to][k][1]+len);
    41                     Min(tmp[j+k][2],f[x][j][1]+f[to][k][1]+len);
    42                     Min(tmp[j+k][2],f[x][j][0]+f[to][k][2]+len*2);
    43                     Min(tmp[j+k][2],f[x][j][2]+f[to][k][0]+len*2);
    44                 }
    45             size[x]+=size[edge[i].to];
    46             for (int j=0; j<=size[x]; ++j)
    47                 for (int k=0; k<=2; ++k)
    48                     f[x][j][k]=min(f[x][j][k],tmp[j][k]);
    49         }
    50     ans=min(ans,f[x][m][2]);
    51 }
    52 
    53 int main()
    54 {
    55     memset(&INF,0x3f,sizeof(INF));
    56     scanf("%d%d",&n,&m);
    57     for (int i=1; i<=n-1; ++i)
    58     {
    59         scanf("%d%d%d",&u,&v,&l);
    60         add(u,v,l); add(v,u,l);
    61     }
    62     ans=INF; Dfs(1,0);
    63     printf("%d
    ",ans);
    64 }
  • 相关阅读:
    win7如何配置access数据源
    pcA降维算法
    今天的分类
    实现MFC菜单画笔画圆,并且打钩
    多个字符串输出,竖直输出
    端口重用
    安卓快速关机APP
    端口转发
    学习OpenCV
    求解数独
  • 原文地址:https://www.cnblogs.com/refun/p/9774584.html
Copyright © 2011-2022 走看看