uvalive4015 (树上背包)

给一棵树,边上有权值,然后给一个权值x,问从根结点出发, 走不超过x的距离,最多能经过多少个结点。

走过的点可以重复走,所以可以从一个分支走下去,然后走回来,然后再走另一个分支

dp[u][j][0] 表示从u出发,走了j个点,然后不回到u点的最小花费

dp[u][j][1] 表示从u出发,走了j个点,然后回到u点的最小花费

dp[u][j][0] = min(dp[u][j][0], dp[v][k][0]+dp[u][j-k][1]+dis, dp[v][k][1]+dp[u][j-k][0]+2*dis);

可能是当前这个分支不回到u点,那么就是dp[v][k][0] + dp[u][j-k][1] +dis

可能是当前这个分支回到u点(那么u->v的边走两次,那么就是2*dis),但是以前的分支不回到u点,dp[v][k][1] + dp[u][j-k][0] + 2*dis

dp[u][j][1] = min(dp[u][j][1], dp[v][k][1]+ dp[u][j-k][1] + dis)

#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <algorithm>
#include <iostream>
#include <string>
#include <functional>
const int INF = 1 << 30;

/*


树形背包
*/
const int N = 500 + 10;
struct Edge
{
    int to, dis, next;
}g[N*2];
int head[N], e, fa[N];
int dp[N][N][2];
int size[N];
int n, u, v, dis, query[1111];
void addEdge(int u, int v, int dis)
{
    g[e].to = v;
    g[e].dis = dis;
    g[e].next = head[u];
    head[u] = e++;
}
void init()
{
    memset(dp, 0x7f7f7f7f, sizeof(dp));
    memset(head, -1, sizeof(head));
    memset(fa, -1, sizeof(fa));
    e = 0;
}
void dfs(int u, int fa)
{
    dp[u][1][0] = dp[u][1][1] = 0;
    size[u] = 1;
    for (int i = head[u];i != -1;i = g[i].next)
    {
        int v = g[i].to;
        if (v == fa) continue;
        dfs(v, u);
        size[u] += size[v];
        for (int j = size[u];j >= 1;--j)
            for (int k = 1;k <= size[v]; ++k)
            {
                dp[u][j][0] = std::min(dp[u][j][0], std::min(dp[u][j-k][1]+dp[v][k][0] + g[i].dis, dp[u][j-k][0]+dp[v][k][1] + g[i].dis * 2));
                dp[u][j][1] = std::min(dp[u][j][1], dp[u][j-k][1] + dp[v][k][1] + g[i].dis * 2);
            }
        
    }
}
int main()
{
    int tcase = 1;
    while (scanf("%d", &n) ,n)
    {
        init();
        for (int i = 1;i < n;++i)
        {
            scanf("%d%d%d", &u, &v, &dis);
            addEdge(v, u, dis);
            fa[u] = v;
        }
        int root;
        for (int i = 0;i < n;++i)
            if (fa[i] == -1)
                root = i;
        int q, x;
        dfs(root, -1);
        scanf("%d", &q);
        printf("Case %d:
", tcase++);
        while (q--)
        {
            int ans;
            scanf("%d", &x);
            for (int i = 1;i <= n;++i)
                if (dp[root][i][0] <= x || dp[root][i][1] <= x)
                    ans = i;
            printf("%d
", ans);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/justPassBy/p/4782768.html