uva 1407 - Caves(树形dp)

来源:互联网 发布:日立柜机 知乎 编辑:程序博客网 时间:2024/06/10 21:12

题目链接:uva 1407 - Caves


题目大意:给出n,表示有一个以0为根含有n个节点的树,每条边有一个权值,现在给出m次询问,每次询问有一个val值,要求计算在val值下的距离最多能经过多少个节点,一个节点多次移动多算一次。


解题思路:dp[u][i]表示说以u为根,经过i个节点的最短距离,第三维有0和1两种状态,0是经过i个节点后要不用返回u,1是需要返回。这样就有(当考虑一个孩子节点v时):

dp[u][j][0] = min(dp[u][j][0], dp[u][j-x][1]+dp[v][x][0]+val);  

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

dp[u][j][1] = min(dp[u][j][1], dp[u][j-x][1]+dp[v][x][1]+2*val);


#include <stdio.h>#include <string.h>#include <algorithm>#include <vector>using namespace std;const int N = 505;const int INF = 0x3f3f3f3f;struct state {int v, val;state() { };state(int vi, int value) {this->v = vi;this->val = value;}};int n, m, vis[N], cnt[N], dp[N][N][2];vector<state> g[N];void init () {memset(vis, 0, sizeof(vis));memset(dp, INF, sizeof(dp));for (int i = 0; i < n; i++) g[i].clear();int a, b, value;for (int i = 1; i < n; i++) {scanf("%d%d%d", &a, &b, &value);g[a].push_back(state(b, value));g[b].push_back(state(a, value));}}void solve (int u) {vis[u] = cnt[u] = 1;dp[u][1][0] = dp[u][1][1] = 0;for (int i = 0; i < g[u].size(); i++) {int v = g[u][i].v, val = g[u][i].val;if (vis[v]) continue;solve(v);cnt[u] += cnt[v];for (int j = cnt[u]; j > 1; j--) {for (int x = 0; x <= j && x <= cnt[v]; x++) {dp[u][j][0] = min(dp[u][j][0], dp[u][j-x][1]+dp[v][x][0]+val);dp[u][j][0] = min(dp[u][j][0], dp[u][j-x][0]+dp[v][x][1]+2*val);dp[u][j][1] = min(dp[u][j][1], dp[u][j-x][1]+dp[v][x][1]+2*val);}}}}int main () {int cas = 1;while (scanf("%d", &n) == 1 && n) {init();solve(0);printf("Case %d:\n", cas++);int a;scanf("%d", &m);while (m--) {scanf("%d", &a);for (int i = n; i; i--) if (dp[0][i][0] <= a) {printf("%d\n", i); break;}}}return 0;}


2 0