牛客—— 旅游 (树形DP求树的最大独立集)

原题链接

题意:

树的最大独立集定义: 对于一棵有N个结点的无根树,选出尽量多的结点,使得任何两个结点均不相邻(称为最大独立集) ;

对于任意一个点x,都有选和不选两种情况。

我们假设dp[x] [0]表示不选该点的最大值,dp[x] [1] 表示选择该点的最大值。

对于一个点来说,如果选了这个点,就不能选择他的子节点;如果不选这个点,他的子节点又有选和不选两种情况。

所以可以得出转移方程:

dp[x][1]=1;///初始化
dp[x][1]+=dp[j][0];
dp[x][0]+=max(dp[j][0],dp[j][1]);
///j是x的子节点

然后就可以利用dfs从子节点的信息推出父节点的信息。

因为s是必须住的,所以答案就是dp[s] [1];

思路:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
#define I_int ll
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
char F[200];
inline void out(I_int x) {
    if (x == 0) return (void) (putchar('0'));
    I_int tmp = x > 0 ? x : -x;
    if (x < 0) putchar('-');
    int cnt = 0;
    while (tmp > 0) {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0) putchar(F[--cnt]);
    cout<<endl;
}

const int maxn=500000+10;

struct node{
    int e,ne;
}a[maxn*2];
int h[maxn*2],idx;
int dp[maxn][2];

void add(int u,int v){
    a[idx].e=v,a[idx].ne=h[u],h[u]=idx++;
}

void dfs(int u,int fa){
    dp[u][1]=1;
    for(int i=h[u];~i;i=a[i].ne){
        int j=a[i].e;
        if(j==fa) continue;
        dfs(j,u);
        dp[u][0]+=max(dp[j][0],dp[j][1]);
        dp[u][1]+=dp[j][0];
    }
}

int main(){
    memset(h,-1,sizeof h);
    idx=0;
    int n=read(),s=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    dfs(s,-1);
    out(dp[s][1]);
    return 0;
}