UVALive 4015 - Caves(树形DP)

Description

It is said that the people of Menggol lived in caves. A tribe‘s caves were connected to each other with paths. The paths were so designed that there was one and only one path to each cave. So the caves and the paths formed a
tree. There was a main cave, which connected the world outside. The Menggolian always carved a map of the tribe‘s caves on the wall of the main cave.

Scientists have just discovered Menggolian‘s tribe. What a heart-stirring discovery! They are eager to explore it. Since the terrain is very complex and dangerous, they decide to send out a robot.

The robot will be landed into the main cave, where he will begin his adventure. It doesn‘t have to return to the main cave, because the messages of his exploration will be sent immediately to the scientists while he is on the
way.

A robot can only walk x meters before it runs out of energy. So the problem arises: given the map of the tribe‘s caves and a set of
x , how many caves can be explored at most?

Input

There are multiple test cases in the input file. Each test case starts with a single number
n(0n500)
, which is the number of caves, followed by n - 1 lines describing the map. Each of the
n - 1 lines contains three integers separated by blanks:
i , j , and
d(1d10000)
. It means that the i -th cave‘s
parent cave is the j -th cave and the distance is
d meters. A parent cave of cave
i is the first cave to enter on the path from
i to the main cave. Caves are numbered from 0 to
n - 1 . Then there is an integer q(1q1000)
, which is the number of queries, followed by q lines. For one query, there is one integer
x(0x5000000)
, the maximum distance that the robot can travel. n = 0 indicates the end of input file.

Output

For each test case, output q lines in the format as indicated in the sample output, each line contains one integer, the maximum number of caves the robot is able to visit.

Sample Input

3
1 0 5
2 0 3
3
3
10
11
0

Sample Output

Case 1:

2

2

3

题意:一棵n个节点的有根树,树的边有正整数权,表示两个节点之间的距离,你的任务是回答这样的询问,从根节点出发,走不超过x单位的距离,最多能走多少个节点,节点经过多次算一个,对于每次的询问输出:经过节点数最大的值。 注意题目给出的  i, j,d,其中 j 是 i 的父节点。

思路:树形DP,设 d[ i ][ j ][ k ] 表示以第i个节点为根节点的子树机器人访问j个节点走的最少的路程,k==0表示访问完后又回到i节点,k==1 表示访问完后不回来,

则状态转移方程为:

d[x][j+k][0] = min(d[x][j+k][0],d[x][j][0]+d[y][k][0]+len*2);

d[x][j+k][1] = min(d[x][j+k][1],min(d[x][j][1]+d[y][k][0]+len*2,d[x][j][0]+d[y][k][1]+len));

y 表示 x 的儿子,len 表示 x 到 y 的树枝长度。

用 son[ i ] 表示 i 这棵树的节点数。d[i][1][0] = d[i][1][1] = 0, 每个点到自身的距离均为 0 。接下来就是单独考虑它的子节点了,首先考虑如果返回的话,就一种可能就是:它走其他的子树要返回,然后还要对当前的节点要返回。

如果不返回的话,那么它可能走其他的子树要返回,当前的不返回,还有就是当前的子树返回,其他的子树不返回。

还有枚举 son[ i ] 时要从大到小,因为这是 0, 1 背包。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;

const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const double e = 2.718281828459;
const double eps = 1e-8;
const int MAXN = 550;
int dp[MAXN][MAXN][2];
int n, son[MAXN], cnt[MAXN];
vector<int>g[MAXN];

void dfs(int x)
{
    dp[x][1][0] = dp[x][1][1] = 0;
    son[x] = 1;
    for (int i = 0; i < g[x].size(); i += 2)
    {
        int y = g[x][i];
        int len = g[x][i+1];
        dfs(y);
        for(int j = son[x]; j > 0; j--)
        {   // son 数组要从大到小,从小到大会出错
            for (int k = 1; k <= son[y]; k++)
            {
                dp[x][j+k][0] = min(dp[x][j+k][0], dp[x][j][0]+dp[y][k][0]+len*2);
                dp[x][j+k][1] = min(dp[x][j+k][1], min(dp[x][j][1]+dp[y][k][0]+len*2, dp[x][j][0]+dp[y][k][1]+len));
                //printf("dp[%d][%d] 1   =   %d\n", x, j+k, dp[x][j+k][1]);
                //printf("dp[%d][%d] 0   =   %d\n", x, j+k, dp[x][j+k][0]);
            }
        }
        son[x] += son[y];
    }
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    int Case = 1;
    int u, v, w, s;
    while (cin>>n && n)
    {
        for (int i = 0; i <= n; i++)
            g[i].clear();
        memset(cnt, 0, sizeof(cnt));
        for (int i = 1; i < n; i++)
        {
            scanf("%d %d %d", &u, &v, &w);
            cnt[u] = 1;
            g[v].push_back(u);
            g[v].push_back(w);
        }
        s = 0;
        for (int i = 1; i < n; i++)
            if (!cnt[i])
            {
                s = i;
                break;
            }
        memset(dp, INF, sizeof(dp));
        dfs(s);
        int q, x;
        scanf("%d",&q);
        printf("Case %d:\n", Case++);
        while(q--)
        {
            scanf("%d", &x);
            int ans = 1;
            for (int i = 1; i <= n; i++)
            {
                //printf("%d %d\n", dp[s][i][0], dp[s][i][1]);
                if (dp[s][i][0]<=x || dp[s][i][1] <= x)
                    ans = i;
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}
时间: 2024-10-20 10:53:05

UVALive 4015 - Caves(树形DP)的相关文章

UVALive 4015 Caves 树形背包

题目链接:点击打开链接 题意: 给定n个点的有根树(0为根), 下面给出边和边权 一个整数q表示q个询问 每个询问一个数字x ,表示有一个人从根开始走,行走距离不超过x且使得走过不相同的点最多. 问最多能走多少个点. 思路: dp[i][j][0]表示以i为根的子树,以i为起点走了j个不同点且回到i的最小花费. dp[i][j][1]表示不需要回到i的最小花费. 转移的时候就是一个背包 import java.io.PrintWriter; import java.text.DecimalFor

UvaLive 6534 Join two kingdoms 树形DP+二分

链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4545 题意:两个国家A,B,分别有N座城市和Q座城市(1 ≤ N, Q ≤ 4 × 10^4),每个国家里的城市都是树形结构,每条边的权值都是1.现在要随机从两个国家中各选择一个城市来将两个国家连接起来,问连接起来的大国家里面的最长路的期望是多少. 思路:首先用树形DP

UVALive - 2038 Strategic game (无向+记忆化+简单树形DP)

题目链接:https://vjudge.net/problem/UVALive-2038 题意:给定一棵树,选择尽量少的点,使得每个没有选中的结点至少和一个已经选中的结点相邻.输出最少需要选择的节点数.思路:经典的二分图最小顶点覆盖, 也是经典的树形 DP AC代码: #include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; c

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

HDU2196 Computer(树形DP)

和LightOJ1257一样,之前我用了树分治写了.其实原来这题是道经典的树形DP,感觉这个DP不简单.. dp[0][u]表示以u为根的子树中的结点与u的最远距离 dp[1][u]表示以u为根的子树中的结点与u的次远距离 这两个可以一遍dfs通过儿子结点转移得到.显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离: dp[2][u]表示u往上走的最远距离 对于这个的转移,分两种情况,是这样的: dp[2][v] = max( dp[0][u]+w

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

CF 219D Choosing Capital for Treeland 树形DP 好题

一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) 所以一个城市作为首都,可能会有若干边需要改变方向 现在问,选择哪些城市作为首都,需要改变方向的边最少. 输出最少需要改变方向的边数 输出可以作为首都的编号 树形DP 先假定城市1作为首都 令tree(i)表示以i为根的子树 dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数 第一次