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:\n", 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\n", ans); } } return 0; }