*******************************bestcoder题解********************************
Cities 选出K个点v1,v2,...vK使得∑Ki=1∑Kj=1dis(vi,vj)最小. 考虑每条边的贡献,一条边会把树分成两部分,若在其中一部分里选择了x个点,则这条边被统计的次数为x*(K-x)*2. 那么考虑dp[u][i]表示在u的子树中选择了i个点的最小代价,有转移dp[u][i]=minKj=0(dp[u][i−j]+dp[v][j]+j∗(K−j)∗2∗wu,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 }