https://ac.nowcoder.com/acm/problem/15748
题意:
有n个节点n-1条边,由s节点开始,之后每次选择的节点不能选择之前的选择过的节点及其相邻节点。
分析:
n个节点,n-1条边,由s节点开始选择,很明显是一颗以s节点为根节点的树,这是一道树的最大独立集问题,由于n数据有5e5,显然根据数进行暴力搜索可能不太行,我们要用dp对它进行优化,这就是所谓的树形dp了,对树进行动态规划,对此题而言,由子节点推到父节点,即根的子节点传递有用的信息给父节点,最终由父节点再求出最优解。
而每一步的状态只有选择住宿还是不住宿(取或者不取),因此状态转移方程为:
dp[u][0/1] 表示以u为根的子树可以选择的最多的节点数,0表示不选u节点,1表示选择u节点。
dp[u][1]+=dp[t][0];//选择u节点,前面的节点的最优解加上1(当前节点)
dp[u][0]+=max(dp[t][1],dp[t][0]);//不选择u节点,max(选择子节点,不选择子节点)
因此答案为dp[s][1]
代码:
#include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<vector> using namespace std; typedef long long ll; int i,j,n,k,tt,m,t,x,s,y; vector<int>v[500005]; int dp[500005][2]; void dfs(int u,int fa){ dp[u][1]=1;//选择u节点至少为1 for(auto t:v[u]){ if(t==fa){ continue; } dfs(t,u);//递归到叶子节点 dp[u][1]+=dp[t][0];//选择u节点 dp[u][0]+=max(dp[t][1],dp[t][0]);//不选择u节点 } } int main() { scanf("%d%d",&n,&s); for(i=1;i<n;i++){ scanf("%d%d",&x,&y); v[x].push_back(y); v[y].push_back(x); } dfs(s,0); printf("%d",dp[s][1]); }