POJ3342 Party at Hali-Bula(树的最大独立集-树形DP-刷表法)

题意:

给定一个树,选择若干点,使得选择的结点中任一结点不会和它的子结点同时选择,求能选结点最大数量。同时判断方案数是否为一。

思路:树的最大独立集,用树形dp,dfs一遍找每个结点的父亲,是为了从下向上刷每个结点儿子的最大独立集和and每个结点孙子的最大独立集和的表

判断方案数是否唯一同样在树形dp的同时递推判断即可

算法复杂度可以是线性

//248K	0MS	C++
#include<cstdio>
#include<iostream>
#include<cstring>
#include<iostream>
#include<map>
#include<string>
#include<vector>
using namespace std;
int n;
bool flag;
const int N = 220;
map<string,int >name;
struct Edge
{
    int v;
    Edge(int _v=0) :v(_v){};
};
vector<Edge> es[N];
int dp[N];
int fa[N]; //每个节点的父亲
int dep[N]; //每个结点的深度
int sum_s[N]; //每个结点儿子的最大独立集和
bool viss[N],visgs[N],visdp[N]; //分别标记对应结点的dp值,孙子的最大独立集和,儿子的最大独立集和 他们是否名单唯一
int sum_gs[N]; //每个结点孙子的最大独立集和
int mdep;
void dfs(int u,int pa)
{
    if(pa==-1) dep[u]=0;
    else dep[u] = dep[pa]+1;
    mdep=max(mdep,dep[u]);
    int sz=es[u].size();
    for(int i=0;i<sz;i++)
    {
        int v=es[u][i].v;
        if(v!=pa) dfs(v,fa[v]=u);
    }
}
void ini()
{
    flag=0;
    mdep=-1;
    name.clear();
    for(int i=0;i<n;i++) es[i].clear();
    memset(sum_gs,0,sizeof(sum_gs));
    memset(sum_s,0,sizeof(sum_s));
    memset(viss,0,sizeof(viss));
    memset(visgs,0,sizeof(visgs));
    memset(visdp,0,sizeof(visdp));
}
int main()
{
    while(scanf("%d",&n),n)
    {
        ini();
        int sz=0;
        string empl,boos;
        cin>>boos;
        if(!name.count(boos))
            name[boos]=sz++;
        for(int i=0;i<n-1;i++)
        {
            cin>>empl>>boos;
            if(!name.count(empl))
                name[empl]=sz++;
            if(!name.count(boos))
                name[boos]=sz++;
            int u=name[empl],v=name[boos];
            es[u].push_back(Edge(v));
            es[v].push_back(Edge(u));
        }
        dfs(0,-1);
        for(int l=mdep;l>=0;l--)
            for(int i=n-1;i>=0;i--)
            {
                if(dep[i]==l)
                {
                    if(sum_s[i]>1+sum_gs[i])
                    {
                        dp[i]=sum_s[i];
                        visdp[i]=viss[i];
                    }
                    else if(sum_s[i]<1+sum_gs[i])
                    {
                        dp[i]=1+sum_gs[i];
                        visdp[i]=visgs[i];
                    }
                    else
                    {
                        dp[i]=sum_s[i];
                        visdp[i]=true;
                    }
                    if(l>=1)
                    {
                        sum_s[fa[i]] +=dp[i];
                        viss[fa[i]] |= visdp[i];
                    }
                    if(l>=2)
                    {
                        sum_gs[ fa[fa[i]] ] += dp[i];
                        visgs[fa[fa[i]]] |= visdp[i];
                    }
                }
            }
        printf("%d ",dp[0]);
        if(visdp[0]) puts("No");
        else puts("Yes");
    }
    return 0;
}
时间: 2024-10-02 04:09:14

POJ3342 Party at Hali-Bula(树的最大独立集-树形DP-刷表法)的相关文章

2014 Super Training #9 E Destroy --树的直径+树形DP

原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其他点的最远距离最小).现在你要破坏所有叶子节点到根节点的连通,每条边破坏都需要一定能量.你有一个能量为power的武器,能破坏能量小于等于power的任何路.求最少需要的power. 解法参考博客:http://blog.csdn.net/gzh1992n/article/details/86511

hdu1520 Anniversary party(最大独立集 树形dp)

题目链接:点击打开链接 题目描述:现有一棵树,树上每个结点都有一个权值,问从中选一些点,这些点两两之间不直接连接,问权值最大为多少? 解题思路:很裸的一道树上最大独立集问题 树形dp即可 dp[i][0]:不选i节点 dp[i][0]+=max(dp[t][0],dp[t][1]); dp[i][1]:选i节点     dp[i][1]+=dp[t][0]; 代码: #pragma comment(linker,"/STACK:1024000000,1024000000") #incl

POJ 1655 Balancing Act[树的重心/树形dp]

Balancing Act 时限:1000ms Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.Find out the

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

POJ 1655 BalanceAct 3107 Godfather (树的重心)(树形DP)

参考网址:http://blog.csdn.net/acdreamers/article/details/16905653 树的重心的定义: 树的重心也叫树的质心.找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡. 通常利用树形DP找重心: BalanceAct: http://poj.org/problem?id=1655 题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最

[模拟赛10.12] 老大 (二分/树的直径/树形dp)

[模拟赛10.12] 老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n ? 1 条边的无向连通图),由于新建的办公室太大以至于要将奖杯要分放在两个不同的地方以便同学们丢硬币进去开光,OB 想请你帮帮他看看奖杯放在哪两个办公室使得在任意一个在劳模办公室做题的小朋友能最快地找到奖杯来开光. 一句话题意:给出一个 n 个点的树,在两个合适且不同的点放上奖杯,使得每个点到最近的奖杯距离最大值最小. 输入

肥宅快乐树 换根+树形DP/dfs

肥宅快乐树是一棵神秘而巨大的树,它长有许多枝条和节点,每条枝连接树中两个节点,每个节点上都长有一瓶肥宅快乐水. 何老板是肥宅快乐水的资深爱好者.历经艰难,他终于找到了这棵传说中的快乐树.他想要获取树上所有的快乐水,迫不及待地想从树根往树上爬. 每经过一条树枝都会耗费一定体力.而且快乐树自带防御功能,即每条枝上都有一个一次性陷阱,一旦踏上该枝,何老板就会被立即弹射回地面,他得重新从根往上爬. (注1:一次性陷阱是指,陷阱只在第一次经过该枝时有效) (注2:从i号点回到i的父亲节点,不耗费体力) 每

poj1655 树的重心 树形dp

处理处每个节点的孩子有几个,和树的大小就好了. #include<cstdio> #include<queue> #include<cstring> #include<iostream> #include<algorithm> #define INF 99999999 using namespace std; const int MAXN = 20010; struct node { int to; int v; int next; }edge[