UVa 1220 Hali-Bula的晚会(树的最大独立集)

https://vjudge.net/problem/UVA-1220

题意:

公司里有n个人形成一个树状结构,即除了老板以外每个员工都有唯一的直属上司。要求选尽量多的人,但不能同时选择一个人和他的直属上司。输出最多能选多少人并判断是否唯一。

思路:

树的最大独立集问题。就是需要额外判定是否是唯一的。

因为输入的都是人名,所以首先就是用map容器来处理,上下属的关系就用vector容器来处理。

d[u][1]表示以u为根的子树中,选u点能得到的最大人数,f[u][1]判断这种方案是否唯一。

d[u][0]表示以u为根的子树中,不选u点能得到的最大人数,f[u][0]判断这种方案是否唯一。

状态转移方程其实不是很难。首先分析d[u][1],因为u选了,所以u的子结点都不能选,它的子节点的状态只能是这样的,所以此时d[u][1]=sum(d[v][0]|v是u的子节点)。容易想到f[v][0]都为唯一时,f[u][1]才是唯一的。

其次是d[u][0],此时u的子节点可选可不选,所以我们需要挑选出更大的那个,每个子节点都是这样处理,最后像上面那样加起来就可以了。转移方程就是d[u][0]=sum(max(d[v][0],d[v][1]))。方案唯一值的判定和上面是一样的,就是分析你所挑选的更大的那个。

根结点值依赖于子节点,所以需要用DFS来处理

 1 #include<iostream>
 2 #include<string>
 3 #include<cstring>
 4 #include<vector>
 5 #include<algorithm>
 6 #include<map>
 7 using namespace std;
 8
 9 const int maxn = 200+5;
10
11 int n, cnt;
12 string s1, s2;
13
14 int d[maxn][2], f[maxn][2];
15
16 map<string, int> id;
17 vector<int> sons[maxn];
18
19
20 void solve(int u)
21 {
22     //最下属的只有两种情况
23     if (sons[u].size() == 0)
24     {
25         d[u][0] = 0;
26         d[u][1] = 1;
27         return;
28     }
29     int k = sons[u].size();
30
31     for (int i = 0; i < k; i++)
32     {
33         int son = sons[u][i];
34         //树形的DFS
35         solve(son);
36         d[u][1] += d[son][0];
37         //一旦有子节点不唯一,它也不唯一
38         if (!f[son][0])    f[u][1] = 0;
39         //u不选时,它的子节点可选可不选,此时需要选个大的
40         d[u][0] += max(d[son][1], d[son][0]);
41
42         //判断是否唯一
43         if (d[son][0]>d[son][1] && !f[son][0])             f[u][0] = 0;
44         else if (d[son][1] > d[son][0] && !f[son][1] )     f[u][0] = 0;
45         else if (d[son][0] == d[son][1])                   f[u][0] = 0;
46
47     }
48     ++d[u][1];
49 }
50
51 int main()
52 {
53     //freopen("D:\\txt.txt", "r", stdin);
54     while (cin >> n && n)
55     {
56         memset(d, 0, sizeof(d));
57         //初始化都为唯一
58         for (int i = 0; i <= n; i++)
59             f[i][1] = f[i][0] = 1;
60         id.clear();
61         for (int i = 1; i <= n; i++)
62             sons[i].clear();
63         cnt = 0;
64
65         cin >> s1;
66         id[s1] = ++cnt;
67         for (int i = 1; i < n; i++)
68         {
69             cin >> s1 >> s2;
70             if (!id[s1])  id[s1] = ++cnt;
71             if (!id[s2])  id[s2] = ++cnt;
72             sons[id[s2]].push_back(id[s1]);
73          }
74
75         solve(1);
76
77         if (d[1][0] == d[1][1])  printf("%d No\n", d[1][0]);
78         else if (d[1][0] > d[1][1])  printf("%d %s\n", d[1][0], !f[1][0] ? "No" : "Yes");
79         else  printf("%d %s\n", d[1][1], !f[1][1] ? "No" : "Yes");
80     }
81     return 0;
82 }
时间: 2024-12-20 10:12:46

UVa 1220 Hali-Bula的晚会(树的最大独立集)的相关文章

Uva 1220,Hali-Bula 的晚会

题目链接:https://uva.onlinejudge.org/external/12/1220.pdf 题意: 公司n个人,形成一个数状结构,选出最大独立集,并且看是否是唯一解. 分析: d(i) 是 节点 i 的最优值, i 只有两种决策,就是选和不选. 转移方程: d(i) = max {1+Σ1d(j),Σ2d(j)}; Σ1是所有孙子节点,Σ2是所有儿子节点. 那么状态的定义d(i,0),节点 i 不选,d(i,1),节点 i 选. 那么状态转移方程就是: 是否唯一 f(v,0) =

Party at Hali-Bula UVA - 1220 (树形dp)

Party at Hali-Bula UVA - 1220 题意:选一个公司的人去参加晚会,要求不能选有直接上下级关系的人,问最多选多少人去,并判断方案是否唯一. 树的最大独立集,并判断是否唯一. d[u][1]表示选u,d[u][0]表示不选u f[u][1]==1表示选u的情况下唯一,f[u][1]==0表示不唯一 f[u][0]为不选u的情况下的唯一性 1 #include <cstdio> 2 #include <bits/stdc++.h> 3 using namespa

uva 1220 - Party at Hali-Bula 【入门树形dp】

题目:uva 1220 - Party at Hali-Bula 题意:一个公司员工要举行聚会,要求任意一个人不能和他的直接上司同时到场,一个员工只有一个支系上司,现在求最多有多少人到场,并且方案是否唯一 分析:分析发现是要求一个树的最大独立集.这里可以用树形dp解决. 定义dp[x][0]:表示在 i 点不选 i 点的以 x 为子树的最大独立集 而dp[x][1] 表示x到场的最大独立集 定义f [x][0]:表示以x为根且x点不选的子树是否唯一 ,f[x][1]表示以x为根且x选的子树是否唯

UVA - 11983 Weird Advertisement (线段树求并面积)

Description G Weird Advertisement Renat Mullakhanov (rem), one of the most talented programmers in the world, passed away on March 11, 2011. This is very sad news for all of us. His team went to ACM ICPC World Finals - 2004, placed 4th and won gold m

UVa 10308 Roads in the North 树的直径

题目来源:UVa 10308 Roads in the North 题意:求距离最远的2点之间的距离 思路:裸的树的直径 或者树形DP #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn = 100010; struct node { int to, w; node(){} node(int to, int w): to(to), w(w) {

UVA 11983 Weird Advertisement(线段树求矩形并的面积)

UVA 11983 题目大意是说给你N个矩形,让你求被覆盖k次以上的点的总个数(x,y<1e9) 首先这个题有一个转化,吧每个矩形的x2,y2+1这样就转化为了求N个矩形被覆盖k次以上的区域的面积 由于坐标很大,首先考虑的就是将坐标离散化,然后建立线段树tree[][K],表示x的某个区间被覆盖了K次(大于K次算K次)的实际长度,在计算时把矩形转化为一系列横线段(就是说将一个矩形拆开为两条线段,下面的标记为1,上面的标记为-1(这里的标记很有技巧)),然后将这些线段按照y值的从小到达排序(y值相

Uva - 1513 Moive collection ( 模拟栈 + 树状数组基本操作 )

Uva - 1513 Moive collection ( 模拟栈 + 树状数组基本操作 ) 题意: 一个书架,原来所有的书都是按顺序摆好的,书的编号从1开始到n 操作: 取出一本书,统计在这本书之前有多少本书,统计完之后,将这本书放在书架的第一位. 如:  1 2 3 4 5取4   4 1 2 3 5 (取之前,有3本书在4前面,取完后,将4放在栈顶)取4   4 1 2 3 5 (取之前,有0本书在4前面,取完后,将4放在栈顶)取2   2 4 1 3 5 (取之前,有2本书在2前面,取完

UVA - 1220 Party at Hali-Bula

题目大意:n 个人形成一个关系树,每个节点代表一个人,节点的根表示这个人的唯一的直接上司,只有根没有上司.要求选取一部分人出来,使得每 2 个人之间不能有直接的上下级的关系, 求最多能选多少个人出来,并且求出获得最大人数的选人方案是否唯一. 解题思路:分析发现是要求一个树的最大独立集.这里可以用树形 DP 解决. 定义dp[x][0]:表示在 i 点不选 i 点的以 x 为子树的最大独立集 而dp[x][1] 表示x到场的最大独立集 定义f [x][0]:表示以x为根且x点不选的子树是否唯一 ,

树的最大独立集

p280 9.4.2 原问题d(i)是以i为根节点,子问题是以i的儿子节点和以i的孙子节点为根节点. 讲解中的“当计算出一个d(i)后,用它去更新i的父亲和祖父节点的累加值”,对应到代码,需要从树的叶子节点开始计算d(i),可以用dfs 下面是 poj 2342的代码,例题9-13 UVa 1220 对应 poj 3342 #define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<cstdlib> #include<c