luogu P1352 没有上司的舞会 详解

没有上司的舞会

由于每个人(除了根节点)都有直接上司,所以我们可以把它看作一棵树

通过分析,我们不难看出这道题考的是树形动态规划( 树形 D P 树形DP 树形DP

首先我们得先找到那个根节点, r o o t root root

我们可以把每个节点是否有直接上司存在一个数组 b o o k book book 中布尔值为 t r u e true true 表示节点 i i i 有上司,反之没有

int check()//返回值为根节点编号
{
    for(int i=1;i<=n;i++)
    {
        if(book[i]==false)
        {
            return i;
		}
    }
}
bool book[MAXN];
for(int i=1;i<n;i++)
{
    scanf("%d%d",&u,&v);
    book[v]=true;
}
root=check();

这时候,我们就需要分析一下本题的状态转移方程

以一个数组 f [ M A X N ] [ 2 ] \tt f[MAXN][2] f[MAXN][2] 来表示状态

其中 f [ i ] [ 0 ] f[i][0] f[i][0] 表示以节点 i i i 为根节点的子树的最优快乐指数

状态转移方程
f [ i ] [ 0 ] = ( ∑ j = b [ s o n s ] i = a [ i ] [ s o n s ] ) m a x ( f [ i ] [ 0 ] , f [ i ] [ 1 ] ) ; f [ i ] [ 1 ] = ( ∑ j = b [ s o n s ] i = a [ i ] [ s o n s ] ) + w [ i ] \tt f[i][0]=\left(\sum^{i=a[i][sons]}_{j=b[sons]}\right)max(f[i][0],f[i][1]); \tt f[i][1]=\left(\sum^{i=a[i][sons]}_{j=b[sons]} \right) + w[i] f[i][0]= j=b[sons]i=a[i][sons] max(f[i][0],f[i][1]);f[i][1]= j=b[sons]i=a[i][sons] +w[i]

我们可以用一个深搜 d f s dfs dfs 来遍历整棵树

每次搜索以一个节点为跟的子树,搜到叶子节点后回溯,更新动规需要使用到的son

深搜代码:

void dfs(int u)
{
	f[u][1]=w[u];
	for(int i=0;i<b[u];i++)
	{
		int son=a[u][i];
		dfs(son);
		f[u][0]+=max(f[son][0],f[son][1]);
		f[u][1]+=f[son][0];
	}
	return;
}

完整版代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=6*1e3+5;
int n,f[MAXN][2],b[MAXN],w[MAXN];
vector<int> a[MAXN];
int root;
bool book[MAXN];
int check()
{
	for(int i=1;i<=n;i++)
	{
		if(book[i]==false)
		{
			return i;
		}
	}
}
void dfs(int u)
{
	f[u][1]=w[u];
	for(int i=0;i<b[u];i++)
	{
		int son=a[u][i];
		dfs(son);
		f[u][0]+=max(f[son][0],f[son][1]);
		f[u][1]+=f[son][0];
	}
	return;
}
int u,v;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&w[i]);
	}
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		a[v].push_back(u);
		b[v]++;
		book[u]=true;
	}
	root=check();
	dfs(root);
	printf("%d\n",max(f[root][0],f[root][1]));
	return 0;
}

AC记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值