题意:一棵带权树,有K个机器人从原点S出发,问最小花费多少才能遍历所有结点。
思路:树形DP题,一开始想到的状态是三维的,仔细思考一下发现会超时,后来参考了网上的解题报告,发现了回来的机器人最多只要一个(如果有多个的话必定可以证明花费多于一个的)这样用dp[i][0]表示有一个机器人回来的情况,1-k表示用k个机器人遍历以i为根的子树的最小花费。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao/ 4 * Last modified : 2014-04-03 18:10 5 * Filename : hdu_4003.cpp 6 * Description : 7 * ************************************************/ 8 9 #include <iostream> 10 #include <cstdio> 11 #include <cstring> 12 #include <cstdlib> 13 #include <cmath> 14 #include <algorithm> 15 #include <queue> 16 #include <stack> 17 #include <vector> 18 #include <set> 19 #include <map> 20 #define MP(a, b) make_pair(a, b) 21 #define PB(a) push_back(a) 22 23 using namespace std; 24 typedef long long ll; 25 typedef pair<int, int> pii; 26 typedef pair<unsigned int,unsigned int> puu; 27 typedef pair<int, double> pid; 28 typedef pair<ll, int> pli; 29 typedef pair<int, ll> pil; 30 31 const int INF = 0x3f3f3f3f; 32 const double eps = 1E-6; 33 const int LEN = 100010; 34 vector<pii> Map[LEN]; 35 int dp[LEN][11], N, S, K; 36 37 void dfs(int v, int f){ 38 for(int i=0; i<Map[v].size(); i++){ 39 int ch = Map[v][i].first, val = Map[v][i].second; 40 if(ch != f){ 41 dfs(ch, v); 42 for(int k=K; k>=0; k--){ 43 dp[v][k] += dp[ch][0] + 2*val; 44 for(int j=1; j<=k; j++){ 45 dp[v][k] = min(dp[v][k], dp[v][k-j] + dp[ch][j] + j*val); 46 } 47 } 48 } 49 } 50 } 51 52 int main() 53 { 54 // freopen("in.txt", "r", stdin); 55 56 int a, b, c; 57 while(scanf("%d%d%d", &N, &S, &K)!=EOF){ 58 memset(dp, 0, sizeof dp); 59 for(int i=0; i<LEN; i++) Map[i].clear(); 60 for(int i=0; i<N-1; i++){ 61 scanf("%d%d%d", &a, &b, &c); 62 Map[a].PB(MP(b, c)); 63 Map[b].PB(MP(a, c)); 64 } 65 dfs(S, -1); 66 printf("%d ", dp[S][K]); 67 } 68 return 0; 69 }