题目大意:一棵有n个节点的有根树,树的边有正整数权,表示两个节点之间的距离,你的任务是从根节点出发,走不超过x单位距离的,最多能经过多少个节点,每个节点只能计算一次

解题思路:用dis[u][v]表示u节点和v节点之间的距离,v节点是u节点的子节点
用dp[u][i][0]表示从u节点出发经过i个节点,最后没有回到节点u所走的最短路径
那么dp[u][i][0] = min(dp[u][i-k][1] + dp[v][k][0] + dis[u][v], dp[u][i-k][0] + dp[v][k][1] + 2 * dis[u][v])
dp[u][i][1]表示从u节点出发经过i个节点,最后回到了节点u所走的最短路径
则dp[u][i][1] = dp[u][i-k][1] + dp[v][k][1] + 2 * dis[u][v]

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define maxn 510
using namespace std;
vector<int> tree[maxn];

int dp[maxn][maxn][2], n, dis[maxn][maxn], son[maxn], vis[maxn];
int dfs(int cur) {

    son[cur] = 1;
    int size = tree[cur].size();

    for(int i = 0; i < size; i++) 
        son[cur] += dfs(tree[cur][i]);  

    dp[cur][1][0] = dp[cur][1][1] = 0;
    for(int i = 0; i < size; i++) {
        int next = tree[cur][i];
        int len = dis[cur][next];

        for(int j = son[cur]; j >= 1; j--) 
            for(int k = 1; k <= son[next] && k < j; k++) {
                dp[cur][j][1] = min(dp[cur][j][1], dp[cur][j-k][1] + dp[next][k][1] + 2 * len);
                dp[cur][j][0] = min(dp[cur][j][0], dp[cur][j-k][1] + dp[next][k][0] + len);
                dp[cur][j][0] = min(dp[cur][j][0], dp[cur][j-k][0] + dp[next][k][1] + 2 * len);
            }
    }
    return son[cur];
}

int main() {
    int mark = 1;
    while(scanf("%d", &n) == 1 && n) {

        for(int i = 0; i < n; i++)
            tree[i].clear();    
        memset(dp,0x3f,sizeof(dp));
        memset(vis,0,sizeof(vis));
        int x, y, d;
        for(int i = 0; i < n - 1; i++) {
            scanf("%d%d%d", &x, &y, &d);
            tree[y].push_back(x);
            dis[y][x] = d;  
        }
        dfs(0);
        int cnt, MAX;
        printf("Case %d:\n",mark++);
        scanf("%d", &cnt);
        while(cnt--) {
            scanf("%d", &MAX);
            for(int i = n; i >= 0; i--)
                if(dp[0][i][0] <= MAX){
                    printf("%d\n", i);
                    break;  
                }   
        }
    }
    return 0;
}