木の形をしたdpの説明(後悔することはありません)

この記事を読む前に、基本的なdpをある程度理解していて、よく学ばなくてもこの説明を理解できることを願っています。

質問の例から始めましょう:

ツリー型のdpのよく知られたエントリの例:ボール
トピックへのボスのリンクなし
ここに画像の説明を挿入
ツリー型のdpはツリーベースのdpです(ツリーと言う必要はありません。データ構造であるか離散であるかは関係ありません。数学、学ぶ必要があるようです)
ここでは、ツリーを保存する方法について説明します

#include<iostream>
#include<math.h>

using namespace std;
const int N=6000+10;
int last[N],ne[N],edge[N],cnt;
bool biao[N];
void add(int a, int b){
    
    
    edge[cnt] = b;
    ne[cnt] = last[a];
    last[a] = cnt++;
}

int main()

{
    
    
  int n;
  cin>>n;//n名员工
  int a,b;
  for(int i=1;i<n;i++)//n-1条边
  {
    
    cin>>a>>b;//b是a的直接上司
    add(a,b);
    
  
    
  }
  
    
}

そのようなツリーがあると仮定して、それをシミュレートしましょう
ここに画像の説明を挿入
。last
[a]配列から1の子ノードを見つける必要があるとすると、cntを取得できます。このcntを介して、dge [cntの子ノードbを取得できます。 ] = b配列

void add(int a, int b){
    
    
    edge[cnt] = b;
    ne[cnt] = last[a];
    last[a] = cnt++;
}

このコードcnt ++は最後に実行されることに注意してください。
実際、これを書くこともできます。

void add(int a, int b){
    
    
    cnt++//此时cnt是从一开始,遍历时需要注意一下
    edge[cnt] = b;
    ne[cnt] = last[a];
    last[a] = cnt;
}

このように書くこともできます

void add(int a, int b){
    
    
    
    edge[cnt] = b;
    ne[cnt] = last[a];
    last[a] = cnt;
    cnt++}

lastcntの値がlast [a]に提供される場合、last [a]の値は、aが前回親ノードであったときのcntの値であり、last [a]はすでに値に変更されています。この時点でのcntのne [cnt]に割り当てられ、このcntはlast [a]に割り当てられます。
要約すると、cntはlast [a]によって取得され、子ノードはedge [cnt]によって取得されます。子ノードはne [cnt]によって取得できます。前回aが親ノードだったときのcntなど。

成果を学び、私たちはこの質問を見始めることができます;
またはこのレッスンツリーですか

ここに画像の説明を挿入
私たちが追求される最大値は、右のサブツリーは3を選択していない、と1の重量は、最後に追加されたときに、左部分木が2プラス最大値を選択しない最大値であり、1を選択したと仮定し、
我々が行うと仮定(右のサブツリーの3を選択し、右部分木のために3を選択し、ではない)、最大+(左サブツリーの2を選択しないで、左のサブツリーの2を選択)の最大値は最大で必要とされるもの、1を選択しないで、
あなたを得ますノード1の最大値であり、すべてのノードはこれに基づくことができます。方程式はこの状態の最大値を見つけます。
以下のコードを見てみましょう
。c++コード

#include<iostream>
#include<math.h>
#include<string.h>
using namespace std;
const int N=6000+10;
int last[N];
int ne[N],edge[N],cnt=1;
bool biao[N];
void add(int a, int b){
    
    
    edge[cnt] = b;
    ne[cnt] = last[a];
    last[a] = cnt++;
}
int dp[N][2];

int a[N];
void dps(int root)
{
    
    

   dp[root][0]=0;//不选root号节点;
   dp[root][1]=a[root];//选root号节点


   for(int i=last[root];i>=1;i=ne[i])
   {
    
    
       int j=edge[i];
       dps(j);
       dp[root][0]+=max(dp[j][0],dp[j][1]);
       dp[root][1]+=dp[j][0];
   }


}



int main()

{
    
    
  int n;
  cin>>n;
  for(int i=1;i<=n;i++)
    cin>>a[i];
  //因为0包含的有边
  int x,y;
  
  for(int i=1;i<n;i++)//n-1条边
  {
    
    cin>>x>>y;//y是x的直接上司
    add(y,x);


    biao[x]=true;//a有父节点b
  }
  int v=1;
  while(biao[v])v++;//找到没有父节点的点
  dps(v);


    cout<<max(dp[v][1],dp[v][0]);
}

Javaコード:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

public class Main{
    
    
    static int N = 6010;
    static int[] happy = new int[N];
    static int[] h = new int[N];
    static int[] e = new int[N];
    static int[] ne = new int[N];
    static int idx = 0;
    static int[][] f = new int[N][2];
    static boolean[] has_fa = new boolean[N];
    static void add(int a,int b)
    {
    
    
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx ++;
    }
    static void dfs(int u)
    {
    
    
        f[u][1] = happy[u];
        for(int i = h[u]; i != -1;i = ne[i])
        {
    
    
            int j = e[i];
            dfs(j);

            f[u][1] += f[j][0];
            f[u][0] += Math.max(f[j][1], f[j][0]);
        }
    }
    public static void main(String[] args) {
    
    
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        for(int i = 1;i <= n;i ++) happy[i] = scan.nextInt();
        Arrays.fill(h, -1);
        for(int i = 0;i < n - 1;i ++)
        {
    
    
            int a = scan.nextInt();
            int b = scan.nextInt();
            add(b,a);
            has_fa[a] = true;
        }
        int root = 1;
        while(has_fa[root]) root ++;
        dfs(root);

        System.out.println(Math.max(f[root][0], f[root][1]));
    }
}


同様に、この質問を見てみましょう:
タイトルリンク
ここに画像の説明を挿入

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 100010,M=N*2;
int h[N],e[M],ne[M],w[N],idx;
int n;
LL f[N];
void add(int a,int b)
{
    
    
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int father)
{
    
    
    f[u]=w[u];
    for(int i=h[u];~i;i=ne[i])
    {
    
    
        int j = e[i];
        if(j!=father)//不能让它倒回去
        {
    
    
            dfs(j,u);
            f[u]+=max(0ll,f[j]);
        }
    }
}

int main()
{
    
    
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;++i)cin>>w[i];
    for(int i=0;i<n-1;++i){
    
    
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs(2,-1);
    LL res = f[1];
    for(int i=2;i<=n;++i)res = max(res,f[i]);
    cout<<res<<endl;
    return 0;
}



Javaコード:

import java.util.*;

public class Main {
    
    
    private static int n;
    private static long res;
    private static long[] w;
    private static List<Integer>[] g;
    private static long[] f ;

    public static void main(String[] args) {
    
    
        Scanner sc = new Scanner(System.in);
        n =sc.nextInt();
        w = new long[n+1];
        g = new ArrayList[n+1];
        f = new long[n+1];

        for(int i = 0;i < n+1; i++){
    
    
            g[i] = new ArrayList<Integer>();
        }

        for(int i = 1;i <= n;i ++){
    
    
             w[i] = sc.nextLong();
        }

        for(int i = 0;i < n - 1;i ++)
        {
    
    
            int a = sc.nextInt();
            int b = sc.nextInt();
            g[a].add(b);
            g[b].add(a);
        }

        dfs(1,0);
        res = f[1];
        for(int i = 2; i < n+1; i++){
    
    
            if(res<f[i]){
    
    
                res = f[i]; 
            }
        }
        System.out.println(res);
    }
    /**
    *root作为根所代表的子树有一个最大权和,将其存储在f[root]中
    */
    private static void dfs(int root,int father){
    
    
        f[root] = w[root];
        for(int i = 0; i < g[root].size(); i++){
    
    
            Integer child = g[root].get(i);
            if(child == father){
    
    
                continue;
            }
            dfs(child,root);
            if(f[child] > 0){
    
    
                f[root] += f[child];
            }
        }
    }    
}




おすすめ

転載: blog.csdn.net/jahup/article/details/107203550