题目
题目描述:Cwbc和XHRlyb生活在s市,这天他们打算一起出去旅游。
旅行地图上有n个城市,它们之间通过n-1条道路联通。
Cwbc和XHRlyb第一天会在s市住宿,并游览与它距离不超过1的所有城市,之后的每天会选择一个城市住宿,然后游览与它距离不超过1的所有城市。
他们不想住在一个已经浏览过的城市,又想尽可能多的延长旅行时间。
XHRlyb想知道她与Cwbc最多能度过多少天的时光呢?
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
第一行,两个正整数n和s,表示城市个数和第一天住宿的城市s。
接下来n-1行,每行两个整数x和y,表示城市x与城市y之间有一条双向道路。
输出描述:
第一行,一个非负整数表示答案。
解析
1)知识点
- 这道题明显就是一道树的题目,关于树我们能想到的就是dfs,bfs,树形dp。这道题就是一道树形dp。
2)看题目
- 首先我们看题目意思就是:我们每一个住宿节点相邻的位置是不能住宿的,而不能住宿的节点相邻位置住不住宿都可以。
- 最后我们要求出一共有多少个住宿的节点。
3)算法分析
- 既然我们已经知道这是一道树形dp的题目了,那当然就少不掉这句话:动态规划最重要的就是递推和dp数组的含义。
- 那么首先我们来确定dp数组是干啥用的:我们题目讲到了住宿的节点和节点的住宿问题。
- 所有我们的dp数组就定为一个二维数组:dp[i][0/1]=x:第i个节点(住/不住)时的节点数最大值(答案的最大值)。
- 接下来就是递推了。
- 递推和我们节点之间的关系密不可分:我们这里的节点关系就是我们上面讲到的:住宿点的邻接点不能住宿。
4)算法操作
- 怎么操作呢?首先我们是用递归的方法遍历所有节点进行计算。我们自然就从叶子往上计算。
- 因为如果住下来,就表示答案会加一,所以我们给每一个住宿的情况都先初始化为1:
dp[u][1] = 1;
- 然后我们就开始循环遍历子节点,并递归到叶子为止。
- 接下来我们就可以递推了,按照我们上面所说的规律可以得到转移方程:
dp[u][0] += max(dp[v][0], dp[v][1]); //我如果不住,下一个随便你住不住,所以选最大的 dp[u][1] += dp[v][0]; //我如果住,下一个必须是不住
- 如此递推就可以了。
5)打代码
- 我们还是老方法,先用前向星保存树。
- 然后按照上面的算法操作进行一遍dfs。
- 最后输出一个dp[s][1]就好了,为啥是dp[s][1]?因为我们最后会把答案合并到起点,而起点一定住宿,所以输出这个。
- 看我代码咯~
AC代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//代码预处理区
const int MAX = 5e5 + 7;
int head[MAX], tot;
struct EDGE {
int u, v, w, next;
} edge[MAX << 1];
int n, s;//节点数,起点
int dp[MAX][2];//表示某个节点在(有/没有)的情况下最大待的时间
//全局变量区
void init();//前向星初始化
void add_edge(int u, int v);//前向星加边
void dfs(int u, int fa);//前向星dfs
//函数预定义区
int main() {
IOS;
cin >> n >> s;
init();
for (int i = 1; i <= n - 1; i++) {
int u, v; cin >> u >> v;
add_edge(u, v);
add_edge(v, u);
}
dfs(s, 0);
cout << dp[s][1] << endl;
return 0;
}
void init() {
memset(head, 0, sizeof head); tot = 0;
}
void add_edge(int u, int v) {
tot++;
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
void dfs(int u, int fa) {
dp[u][1] = 1;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (v == fa) continue;
dfs(v, u);
dp[u][0] += max(dp[v][0], dp[v][1]);
//我如果不住,下一个随便你住不住,所以选最大的
dp[u][1] += dp[v][0];
//我如果住,下一个必须是不住
}
}
//函数区
京公网安备 11010502036488号