Acwing 0x50 动态规划~没有上司的舞会

题目链接:https://www.acwing.com/problem/content/287/

题意

Ural大学有N名职员,编号为1-N

他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司。

每个职员有一个快乐指数,用整数Hi 给出,其中 1\leq i\leqslant N

现在要召开一场周年庆宴会,不过,没有职员愿意和直接上司一起参会。

在满足这个条件的前提下,主办方希望邀请一部分职员参会,使得所有参会职员的快乐指数总和最大,求这个最大值。

输入格式

第一行一个整数N

接下来N行,第i行表示i 号职员的快乐指数Hi 。

接下来N-1行,每行输入一对整数L, K,表示KL的直接上司。

最后一行输入0,0。

输出格式

输出最大的快乐指数。

数据范围

1\leq N\leq 6000,
-128\leq Hi\leq 127

题解

f[x][0]表示从以x为根的子树邀请一部分职员参会,并且x不参加舞会时,快乐指数总和的最大值。此时,x的所有子节点(直接下属)可以参会,也可以不参会。

f[x][0]=\sum\limits_{s\epsilon \ Son(x)}max(f[s][0],f[s][1]))

f[x][1]表示从以x为根的子树邀请一部分职员参会,并且x参加舞会时,快乐指数总和的最大值。此时,x的所有子节点(直接下属)都不能参会。

f[x][1]=H[x]+\sum\limits_{s\epsilon \ Son(x)}f[s][0]

我们先找到没有上司的节点root作为根,目标为max(f[root][0],f[root][1]),时间复杂度为O(N)

简单附代码:

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Pair pair<int,int>
#define int long long
#define fir first
#define sec second
namespace fastIO{
	#define BUF_SIZE 100000
	#define OUT_SIZE 100000
	//fread->read
	bool IOerror=0;
//  inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}
	inline char nc(){
		static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
		if(p1==pend){
			p1=buf;pend=buf+fread(buf,1,BUF_SIZE,stdin);
			if(pend==p1){IOerror=1;return -1;}
		}
		return *p1++;
	}
	inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
	template<class T> inline bool read(T &x){
		bool sign=0;char ch=nc();x=0;
		for(;blank(ch);ch=nc());
		if(IOerror)return false;
		if(ch=='-')sign=1,ch=nc();
		for(;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
		if(sign)x=-x;
		return true;
	}
	inline bool read(double &x){
		bool sign=0;char ch=nc();x=0;
		for(;blank(ch);ch=nc());
		if(IOerror)return false;
		if(ch=='-')sign=1,ch=nc();
		for(;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
		if(ch=='.'){
			double tmp=1; ch=nc();
			for(;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
		}
		if(sign)x=-x;
		return true;
	}
	inline bool read(char *s){
		char ch=nc();
		for(;blank(ch);ch=nc());
		if(IOerror)return false;
		for(;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
		*s=0;
		return true;
	}
	inline bool read(char &c){
		for(c=nc();blank(c);c=nc());
		if(IOerror){c=-1;return false;}
		return true;
	}
	template<class T,class... U>bool read(T& h,U&... t){return read(h)&&read(t...);}
	#undef OUT_SIZE
	#undef BUF_SIZE
};using namespace fastIO;using namespace std;
const int N=1e6+5;
const int mod=1e9+7;

int h[N];
bool v[N];
vector<int>son[N];
int f[N][2];


void dp(int x){
  f[x][0]=0;
  f[x][1]=h[x];
  for(int i=0;i<son[x].size();i++){
    int y=son[x][i];
    dp(y);
    f[x][0]+=max(f[y][0],f[y][1]);
    f[x][1]+=f[y][0];
  }
}
signed main(){
  //printf("%lld\n",112233+142536+445566+415263);
  int n;read(n);
  for(int i=1;i<=n;i++)read(h[i]);
  
  for(int i=1;i<n;i++){
    int x,y;read(x,y);
    v[x]=1;
    son[y].push_back(x);
  }
  int a,b;read(a,b);
  int root;
  for(int i=1;i<=n;i++){
    if(!v[i]){root=i;break;}
  }
  
  dp(root);
  printf("%lld\n",max(f[root][0],f[root][1]));
  return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值