树的最大独立集&没有上司的舞会
树的最大独立集题目::
这两道题其实是差不多的,只不过没有上司的舞会多了一个快乐指数,所以这两道题我放到一起来讲。
这两道题都是基础的树形dp题,从题目中我们可以得知,如果一个节点被选了,那么TA的儿子节点就都不能选。
由此我们可以设 dp [ i ] [ 0 ] 为不选这个节点的最大取值。
相应的 dp [ i ] [ 1 ] 就为选这个节点的最大取值。
这样我们就可以得到状态转移方程::
dp [ i ] [ 0 ] = max ( max ( dp [ j ] [ 0 ] ) , max ( dp [ j ] [1 ] ) )
dp [ i ] [ 1 ] = max ( dp [ j ] [ 0 ] ) + 1(+快乐指数)
如果再直观一点的解释就是::
如果不选这个节点:dp [ i ] [ 0 ] = i节点的所有儿子中选这个儿子或者不选这个儿子的最大值
如果选这个节点:dp [ i ] [ 1 ] = i节点的所有儿子中不选这个儿子的最大值 + i节点本身
好像越说越绕了。。。
所以大家尽量理解一下
注意上面的红字就对了
然后还要注意几点
1、需要递归,从叶子节点开始,最后归到根节点上去,输出 max ( dp [ 根 ] [ 0 ] , dp [ 根 ] [ 1 ] )
2、题目说是无根树,所以需要先转换成有根树,只需要以任意一个点作为根节点即可
然后我们就可以上代码了::
(PS::作者太懒,只想给树的最大独立集的代码)
#include<cstdio>
#include<vector>
using namespace std;
inline void read(int &x) {
x=0;
int f=1;
char s=getchar();
while(s<'0'||s>'9') {
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=x*10+s-48;
s=getchar();
}
x*=f;
}
inline void pr(int x) {
if(x<0) {
putchar('-');
x=-x;
}
if(x>9)
pr(x/10);
putchar(x%10+48);
}//快读快输不解释
vector<int>G[6005];//用vector来存这棵树
int n,k,a,b,dp[6005][2];//按上面说的定义
void dfs(int x,int fa) {//递归搜索
dp[x][1]=1;//本身
for(int i=0;i<G[x].size();i++) {//依次找所有的儿子节点中最大的
int v=G[x][i];
if(v==fa)//本身
continue;
dfs(v,x);//从叶子结点开始更新,这样才能一层层得出答案
dp[x][1]+=dp[v][0];//儿子节点只能不选
dp[x][0]+=max(dp[v][0],dp[v][1]);//找最大值更新
}
}
int main() {
read(n);
for(int i=1;i<n;i++)
read(a),read(b),G[a].push_back(b),G[b].push_back(a);//正常读入
dfs(1,0);
pr(max(dp[1][0],dp[1][1]));
}
大概就是这样了,大家有什么不懂的记得在评论区留言哦
觉得好的话就给个关注吧
更多我的博客在这里哟