UVA1407
来源:互联网 发布:知乎 脱发 编辑:程序博客网 时间:2024/06/05 03:33
一定距离走多远
题目描述:
给出n,表示有一个以0为根含有n个节点的树,每条边有一个权值,现在给出m次询问,每次询问有一个val值,要求计算在val值下的距离最多能经过多少个节点,一个节点多次移动多算一次.其中走的路程很大,点一共有500个
题解:
一共有两个重点.(1)点很少,距离很大,用dp的话要dp[u][i] = x,其中i是可以走的点的个数,而不是距离,用x来表示距离,这样之后扫一遍可以小于limit的i就可以.(2)树形dp的走点的个数一定要定两个状态:一定回来和无所谓.本题中:[0]指无所谓,[1]指必须回来.[1]的状态好转移.然而[0]要看v这个儿子边是不是要走出去不回来然后分成两种情况.
重点:
树形dp算一定距离能走多少个点
代码:
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 500 + 10;const int INF = INT_MAX/2 - 10000*3;int n, dp[maxn][maxn][2];struct info{ int to, len, next;};info edge[maxn];int tot, head[maxn];void add_edge(int a, int b, int len){ edge[tot].to = a; edge[tot].len = len; edge[tot].next = head[b]; head[b] = tot; tot++;}void dfs(int u, int fa){ dp[u][1][0] = 0;//初始化.并没有用dp依赖的写法 dp[u][1][1] = 0; for(int i = 2;i <= n;i++) { dp[u][i][1] = INF; dp[u][i][0] = INF; } for(int i = head[u];i!=-1;i = edge[i].next) { int v = edge[i].to, len = edge[i].len; if(v!=fa) { dfs(v, u); for(int i = n;i >= 2;i--) { for(int j = 1;j <= i - 1;j++)//至少走一个点 { dp[u][i][0] = min(dp[u][i][0], dp[u][i - j][0] + dp[v][j][1]+2*len);//这个v儿子边回来,而是其他的边走掉 dp[u][i][0] = min(dp[u][i][0], dp[u][i - j][1] + dp[v][j][0]+len);//这个v儿子边走掉,其他的边都回来 dp[u][i][1] = min(dp[u][i][1], dp[u][i-j][1]+dp[v][j][1]+2*len);//这个简单,都得回来 } } } }}void solve(){ dfs(0, -1); int q; scanf("%d", &q); while(q--) { int x; int ans = 0; scanf("%d", &x); for(int i = 1;i <= n;i++) { if(dp[0][i][0] <= x) { ans = i; } } printf("%d\n", ans); }}int main(){ // freopen("9Iin.txt", "r", stdin); //freopen("9Iout.txt", "w", stdout); int ncase = 0; while(scanf("%d", &n) != EOF) { if(n==0) break; ncase++; printf("Case %d:\n", ncase); memset(head, -1, sizeof(head)); tot = 0; REP_D(i, 1, n - 1) { int a, b, len; scanf("%d%d%d", &a, &b, &len); add_edge(a, b, len); } solve(); } return 0;}
0 0