[每一]树形DP,最大独立子集

https://ac.nowcoder.com/acm/problem/15748
最大独立子集:选出尽量多的点,使得任何两个节点均不相邻,输出一个最大独立集。

最大独立子集

f[i][0/1]表示以i为根时最大独立点的数量,f[][0]--不住 f[][1]--住
初始值为1,
v是u的儿子节点

//AC @author:AROY
#include<bits/stdc++.h>
using namespace std;
#define N 100005
ll n, k[N];
ll ans, f[N][2];//f[][0]--不住 f[][1]--住
ll tot,rt,dis[N],p[N],h[N],ne[N<<1],u[N<<1],wi[N<<1];
void add(int u,int v){p[++tot]=v;ne[tot]=h[u];h[u]=tot;}
void dfs(int u,int fa){
    f[u][0]=0;f[u][1]=1;
    for(int i=h[u];i;i=ne[i])if(p[i]!=fa)
    {
        int v=p[i];
        dfs(p[i],u);
        f[u][1]+=f[v][0];
        f[u][0]+=max(f[v][0],f[v][1]);
    }
}
int main()
{
    int s;
    cin>>n>>s;
    for(int i=0;i<n;++i){
        int u,v;cin>>u>>v;
        add(u,v);add(v,u);
    }
    dfs(s,0);
    cout<<f[s][1];
}

最小点覆盖

对于图G=(V,E)来说,最小点覆盖指的是从V中取尽量少的点组成一个集合,使得E中所有的边都与取出来的点相连
TODO

最小支配集

指的是从V中取尽量少的点组成一个集合,使得对于V中剩余的点都与取出来的点有边相连。
dp[i][0]:表示点i属于支配集,并且以点i为根的子树都被覆盖了的情况下支配集中所包含的的最少点的个数。

dp[i][1]:i不属于支配集,且以i为根的子树都被覆盖,且i被其中不少于1个子节点覆盖的情况下支配集中所包含最少点的个数。

 dp[i][2]:i不属于支配集,且以i为根的子树都被覆盖,且i没被子节点覆盖的情况下支配集中所包含最少点的个数。

  对于第一种状态,dp[i][0]等于每个儿子节点的3种状态(其儿子是否被覆盖没有关系)的最小值之和加1,即只要每个以i的儿子为根的子树都被覆盖,再加上当前点i,所需要的最少点的个数,方程如下:

  

void DP(int u,int p)
{
    dp[u][2]=0;
    dp[u][0]=1;
    bool s=false;
    int sum=0,inc=INF;
    int k;
    for(k=head[u];k!=-1;k=edge[k].next)
    {
        int to=edge[k].to;
        if(to==p)continue;
        DP(to,u);
        dp[u][0]+=min(dp[to][0],min(dp[u][1],dp[u][2]));
        if(dp[to][0]<=dp[to][1])
        {
            sum+=dp[to][0];
            s=true;
        }
        else
        {
            sum+=dp[to][1];
            inc=min(inc,dp[to][0]-dp[to][1]);
        }
        if(dp[to][1]!=INF&&dp[u][2]!=INF)dp[u][2]+=dp[to][1];
        else dp[u][2]=INF;
    }
    if(inc==INF&&!s)dp[u][1]=INF;
    else
    {
        dp[u][1]=sum;
        if(!s)dp[u][1]+=inc;
    }
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务