poj3659 Cell Phone Network(最小支配集-树形dp)

18 篇文章 0 订阅
10 篇文章 0 订阅

题目链接:点击打开链接

题目描述:给定一棵树,从中选取尽量少的点使每个点要么被选中,要么和被选中的点直接相连?

解题思路:树上的最小支配集,树形dp

dp[i][0]:选中i作为支配集

dp[i][1]:不选i作为支配集,但其子节点覆盖了i

dp[i][2]:不选i作为支配集,而且其子节点没有覆盖i


代码:

#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 10010
#define INF 1e9+7
using namespace std;
int head[MAXN],tol;
struct Edge{
    int v,next;
}edge[MAXN*2];
void addEdge(int u,int v){
    edge[tol].v=v;edge[tol].next=head[u];head[u]=tol++;
    edge[tol].v=u;edge[tol].next=head[v];head[v]=tol++;
}
int min(int a,int b){
    return a<b?a:b;
}
int dp[MAXN][3];
int n;
void DP(int u,int p){
    dp[u][2]=0;
    dp[u][0]=1;
    int sum=0,inc=INF;
    int k,to;
    bool s=false;
    for(k=head[u];k!=-1;k=edge[k].next){
        to=edge[k].v;
        if(to==p) continue;
        DP(to,u);
        dp[u][0]+=min(dp[to][0],min(dp[to][1],dp[to][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;
    }
}
int main(){
    while(scanf("%d",&n)!=EOF){
        tol=0;memset(head,-1,sizeof(head));
        int u,v;
        for(int i=0;i<n-1;++i){scanf("%d%d",&u,&v);addEdge(u,v);}
        DP(1,1);
        printf("%d\n",min(min(dp[1][0],dp[1][1]),dp[1][2]+1));
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值