POJ 3342 Party at Hali-Bula(树的最大独立集)

  • 题目大意

    求树的最大独立集节点个数并判断最大独立集是否唯一
    ps:树的最大独立集是指选出尽量多的点使得两两点之间没有边相连

  • 分析

    如果不判断是否唯一这道题可以用贪心来做
    但加了这个条件之后贪心就不好判断了
    考虑动态规划的做法,用 dp[i][0] dp[i][1] 分别表示以 i 节点为根的子树i节点不选和选两种情况下的最大独立集节点数,转移方程就不用多说了。

  • 总结

    这道题输入用的是字符串表示节点,所以一开始需要用map将字符串映射成一个数。
    因为多组数据之间map没有初始化各种RE TLE WA了20+次,最后又因为Yes写成了YES WA了几发,心累

  • 代码

/*
求树的最大独立集节点个数并判断最大独立集是否唯一
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<stack>
using namespace std;
#define  LL  long long int
const int MAXN=2005;
map<string,int> mapp;
int n;
int index;
int tid[MAXN];//tid保存dfs序
int flag;//flag==1表示YES,最大独立集不唯一
int dp[MAXN][2];
int f[MAXN][2];//值为1表示有多种方案
int fa[MAXN];
struct Edge
{
    int v;
    int next;
}edge[MAXN*2];
int edgecount;
int head[MAXN];
void Init()
{
    memset(head,-1,sizeof(head));
    edgecount=0;
    index=0;
    flag=0;
    memset(fa,0,sizeof(fa));
    memset(dp,0,sizeof(dp));
    memset(f,0,sizeof(f));
    memset(tid,0,sizeof(tid));
}
void Add_edge(int u,int v)
{
     edge[++edgecount].v=v;
     edge[edgecount].next=head[u];
     head[u]=edgecount;
}
void In()
{
    mapp.clear();
    int number=0;
    string s;
    string a,b;
    cin>>s;
    mapp[s]=++number;
    for(int i=1;i<n;i++)
    {
        cin>>a>>b;//b是a的boss
        if(mapp.count(a)==0)mapp[a]=++number;
        if(mapp.count(b)==0)mapp[b]=++number;
        Add_edge(mapp[b],mapp[a]);
       // cout<<"edge: "<<mapp[b]<<" "<<mapp[a]<<endl;
    }
}
void Dfs(int u)
{
    tid[++index]=u;
    for(int k=head[u];k!=-1;k=edge[k].next)
    {
        int v=edge[k].v;
        if(v==fa[u])continue;
        fa[v]=u;
        Dfs(v);
    }
}
void Dp()
{
    for(int i=n;i>=1;i--)
    {
        int u=tid[i];
        dp[u][1]=1;
        dp[u][0]=0;
        for(int k=head[u];k!=-1;k=edge[k].next)
        {
            int v=edge[k].v;
            dp[u][1]+=dp[v][0];
            dp[u][0]+=max(dp[v][0],dp[v][1]);
            if(dp[v][0] > dp[v][1] && f[v][0]==1 ) f[u][0]=1;
            else if(dp[v][1] > dp[v][0] && f[v][1]==1)f[u][0]=1;
            else if(dp[v][0]==dp[v][1])f[u][0]=1;
            if(f[v][0]==1)f[u][1]=1;
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        Init();
        In();
        Dfs(1);
        Dp();
        printf("%d ",max(dp[1][0],dp[1][1]));
        if(dp[1][0]>dp[1][1]  && f[1][0]==1)printf("No\n");
        else if(dp[1][1]>dp[1][0]  && f[1][1]==1)printf("No\n");
        else if(dp[1][1]==dp[1][0])printf("No\n");
        else printf("Yes\n");//唯一
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值