The 2018 ACM-ICPC CCPC NING XIA G-Factories

题意:在一棵数的叶子上建k个工厂保证,求两两距离之和的最小值。

思路:如果一个一个叶子节点去考虑去与否太麻烦了,直接考虑该节点的子树上选取几个作为工厂,利用树形DP,dp[u][i]表示的是u节点为根的子树选取了i个叶子作为工厂的最小值。

转移方程:dp[u][i]=min(dp[u][i],dp[u][i-k]+dp[v][k]+w*k*(m-k)),v表示u的子节点,k表示在u的子节点子树上选取个数,w*k*(m-k)表示这条边的贡献。

AC代码:

 1 int n,m,cas;
 2 ll dp[maxn][102];
 3 int siz[maxn];
 4 struct node{
 5     int u;
 6     ll w;
 7     node(int _u,ll _w){
 8         u=_u;
 9         w=_w;
10     }
11 };
12 vector<node>a[maxn];
13 void dfs(int u,int fa){
14     if(a[u].size()==1){
15         dp[u][1]=0;
16         siz[u]=1;
17     }
18     dp[u][0]=0;
19     rep(i,0,a[u].size()-1){
20         int v=a[u][i].u;
21         ll w=a[u][i].w;
22         if(v==fa) continue;
23         dfs(v,u);
24         siz[u]+=siz[v];
25         dp[u][m]=min(dp[u][m],dp[v][m]);
26         for(int j=min(m,siz[u]);j>=1;j--){
27             for(int k=1;k<=min(j,siz[v]);k++){
28                 dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+1ll*w*k*1ll*(m-k));
29             }
30         }
31     }
32 }
33 void init(){
34     rep(i,0,n) a[i].clear();
35     mem(siz,0);
36 //    mem(dp,INF);
37     rep(i,1,n) rep(j,1,m) dp[i][j]=INF;
38 }
39 void run(){
40     n=rd(),m=rd();
41     init();
42     rep(i,1,n-1){
43         int u=rd(),v=rd();
44         ll w=rdll();
45         a[u].push_back(node(v,w));
46         a[v].push_back(node(u,w));
47     }
48     int rt=1;
49     rep(i,0,n){
50         if(a[i].size()>1){
51             rt=i;
52             break;
53         }
54     }
55     rep(i,0,n) dp[i][0]=0;
56     dfs(rt,-1);
57     printf("Case #%d: %lld
",++cas,dp[rt][m]);
58 }
59 signed main()
60 {    
61      int t=rd();
62      while(t--){
63          run();
64     } 
65 //    run();
66     return 0;
67 }
原文地址:https://www.cnblogs.com/zpj61/p/14374604.html