ボスなしのAcWing285プロム(入門ツリーdp)

**
元のタイトルリンク

タイトル説明

**ウラル大学には1〜Nの番号が付けられたN人の従業員がいます。

それらの関係は、プリンシパルによってルート化されたツリーのようなものであり、親ノードは子ノードの直接のボスです。

各従業員には幸福度指数があり、これは整数Hiで与えられます。ここで、1≤i≤Nです。

現在、記念パーティーがありますが、直属の上司との面談に積極的に参加するスタッフはいません。

この条件が満たされていることを前提として、主催者は、会議に参加するすべてのスタッフの幸福度の合計が最大になるように、何人かのスタッフを会議に招待し、最大値を見つけることを望んでいます。

入力形式
最初の行の整数N。

次のN行、i番目の行は従業員iの幸福度指数Hiを表します。

次の行N-1で、各行に整数LとKのペアを入力し、KがLの直接のボスであることを示します。

出力形式
最大の幸福度指数を出力します。

データ範囲
1≤N≤6000、
-128≤Hi≤127

入力例:
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
出力例
5

トピック分析

このトピックでは、最初にマップを作成する(ツリーを作成する)必要があります。各ポイントには重みがありますが、選択するときに、子ノードと親ノードを一緒に選択することはできません。可能な最大重みはどれくらいですか。選択されますか?
たとえば、そのような木を作ることができます。

赤い領域が最良の選択です。
f(i)を設定できます。ルートノードはiの場合に最適な選択であり、状態を転送できないことがわかりました。各親ノードには選挙または選挙なしの2つの状態があるため、子ノードへの影響は異なります
1親ノード。子ノードは選択できません
。2親ノードが選択されていない場合。バイトポイントは選択できるかどうかに関係なく、
ここで1つの次元を追加します。f[i] [1]とf [i] [0]はそれぞれ、親ノードを選択し、親ノードを選択しない場合を示します。

状態遷移
ここに画像の説明を挿入

ノードiの場合、2つの子ノードs1とs2があります。

1親ノードiが選択されている場合、
f [i] [1] = f [s1] [0] + f [s2] [0]; 2親
ノードiが選択されていない場合、
f [i] [0] = max (f [s1] [0]、f [s1] [1])+ max(f [s2] [0]、f [s2] [1])

タイトルのn点に注目。n-1はエッジが1つあるので、ツリーである必要があります。
画像
AcCodeを保存するために、チェーンフォワードスターと同様の方法を採用しました

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define  gold_m main
#define re register
#define Accept return 0;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf =0x3f3f3f3f;
const int maxn=1e6+5;
const int mod = 1e9+7;
const int N=666;
const long double PI=3.1415926535897932384626433832795;
const long double e=2.71828182845904523536028747135266;
typedef pair<int,int>PII;
inline ll read() {
    
    
	ll  x=0;
	bool f=0;
	char ch=getchar();
	while (ch<'0'||'9'<ch)	f|=ch=='-', ch=getchar();
	while ('0'<=ch && ch<='9')
		x=x*10+ch-'0',ch=getchar();
	return f?-x:x;
}
priority_queue<int,vector<int>, greater<int> >heap;
stack<int>st;
int  dp[maxn][2],cnt,root,head[maxn],h[maxn],n,l,k,rt[maxn];
struct wmy {
    
    
	ll u,v,w,next;
} a[maxn];
void add(ll u,ll v) {
    
    
	a[cnt].u=u;
	a[cnt].v=v;
//	a[cnt].w=w;
	a[cnt].next=head[u];
	head[u]=cnt++;
}
void dfs(int  u)
{
    
    
	dp[u][1] =h[u];
	
	for(int i=head[u];i!=-1;i=a[i].next)
	{
    
    
		ll v=a[i].v;
		dfs(v);
		dp[u][1]+=dp[v][0];
		dp[u][0]+=max(dp[v][0],dp[v][1]);
	}
	return ;
}
int   gold_m() {
    
    
	memset(head,-1,sizeof(head));
	n=read();
	for(int i=1 ; i<=n ; i++) h[i]=read();
	for(int i=1 ; i<n; i++) {
    
    
		cin>>l>>k; //有一条由k指向l的线段 
		add(k,l);
		rt[l]++;
	}
	for(int i=1 ; i<=n; i++) {
    
    
		if(rt[i]==0) {
    
    
			root=i;// 如果这个点没有父亲节点,那么这个点一定是根节点,校长节点 
			break;
		}
	}
	dfs(root);
	cout<<max(dp[root][0],dp[root][1]);
	Accept;
}
/*

*/

おすすめ

転載: blog.csdn.net/wmy0536/article/details/104445461