您的位置:首页 > 其它

1272 摘果子(树形dp,dfs)

2018-02-14 17:34 363 查看
Description
树有N个节点,树根为1号节点,这颗果树上有M个节点长出果实(根节点1有可能长出果实),小明要从节点1出发采集这些果实,从一个节点爬到相邻的另一个节点所需要的时间为1,采集果实不需要时间,问如果要采集这M个果实,从节点1出发,并且最后需要回到节点1,最少需要多少的时间。(节点编号1到N)
Input
输入第一行为正整数N和M ( 0 <= M <= N <= 100000 ) 
接下来的N-1行每行输入两个数字a和b表示节点编号a和节点编号b之间有一条边 
最后一行输入M个数字,第i个数字v[i]表示在v[i]号节点上长有果实
Output
对于每个输入,输出一个数字,表示最少需要花费的时间。
4 2
1 2
1 3
2 4
2 3
Sample Input
4
思路:树形dp, 简单说明一下把;
方便说明,假设树是二叉树, 其实都一样; 
假设根结点的左子树,右子树都存在果子;
那么原树的答案是:左子树的答案 + 2 (来回) 与 右子树答案 + 2(来回) 的和  (最终是要回到1的);
如果某一子树中没果子,那这棵子树自然不需要贡献答案给父结点,也不用所谓来回+2了;
不断递归,自然想到用dfs去实现。 结果就是从叶子节点把答案往上传递 。
需要注意的细节就是从某一节点,找子节点时,有可能会找到父节点,因为建树时是双向的(不要试图用单向,会有bug)。#include <iostream>
#include <vector>
#define maxn 100005
using namespace std;
vector<int> E[maxn], dp(maxn), v(maxn);
int dfs(int u, int fa) {
int bo = (v[u] ? 1 : 0);
for(int i = 0; i < (int)E[u].size(); i++) {
int t = E[u][i];
if(t != fa) {
if(dfs(t, u)) {
bo = 1;
dp[u] += dp[t] + 2;
}
}
}
return bo;
}
int main(void) {
int n, m, s, t, k;
cin >> n >> m;
for(int i = 0; i < n - 1; i++) {
cin >> s >> t;
if(s > t) swap(s, t);
E[s].push_back(t);
E[t].push_back(s);
}
for(int i = 0; i < m; i++) {
cin >> k, v[k] = 1;
}
dfs(1, -1);
cout << dp[1] << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: