【ACWing】1074。バイナリーアップルツリー

件名アドレス:

https://www.acwing.com/problem/content/1076/

二股のリンゴの木があります。枝に二股がある場合、それは二股でなければなりません。つまり、息子が1人だけのノードはありません。この木には合計NNがありますNノード、番号111からNNNは、ルート番号でなければなりません1 11ブランチの両端で接続されているノード番号を使用して、ブランチの位置を記述します。リンゴの木は枝が多すぎて剪定が必要です。ただし、一部の枝にはリンゴがあります。保持する必要のある枝の数を考慮して、保持できるリンゴの最大数を見つけます。ここでの予約は決勝と11を指しますポイント1が接続されています。

入力形式:
最初の行には2つの整数NNが含まれていますNQQQはそれぞれ、ツリー内のノードの数と保持されるブランチの数を表します。次のN− 1 N−1N 1行はブランチ情報を表し、各行には3つの整数があり、最初の2つは接続するノードの番号、3番目の番号はブランチ上のリンゴの数です。

出力形式:
出力は1行のみで、保持できるリンゴの最大数を示します。

データ範囲:
1≤Q<N≤1001≤Q<N≤1001Q<N1 0 0
N≠1 N≠1N=1個の
各ブランチ上のりんごは超えない30000 300003 0 0 0 0

アイデアは動的計画法です。してみましょうF [i]の[j]をF [i]の[J]f[i][j]是以 i i は木の根です、せいぜいjjを保ちますj個のブランチでフェッチできるリンゴの最大数。それぞれの息子をルートとするサブツリーをアイテムのグループと見なします。アイテムの各グループは、いくつかの方法で取得できます。たとえば、子の合計はx 1、x 2、... X_1、x_2、です。 ..バツ1バツ2、ときに考慮子供XS x_sバツSf [xs] f [x_s]を計算しますf [ xS] 0、1、2、...、J − 1 0,1,2、...、j-1と見なすことができます0 1 2 j1本の枝(それがでてしまいますので、1 1ポイント1は接続されたツリーのルートであるため、i→xi \ to xxを取る必要があります)、したがって: fs [i] [j] =max⁡{fs− 1 [i] [j]、max⁡0≤k≤j− 1 fs − 1 [i] [j − k − 1 ] + f [xs] [k] + ∣(i、xs)∣} f_s [i] [j] = \ max \ {f_ {s-1} [i] [j]、\ max_ {0 \ le k \ le j-1} f_ {s-1} [i] [jk-1] + f [x_s] [k] + |(i、x_s)| \}fS[ i ] [ j ]=最大{ fS - 1[ i ] [ j ] 0 K J - 1最大fS - 1[ i ] [ jk1 ]+f [ xS] [ k ]+i バツS| }内の式のfs F_SfS最初のssのみが考慮されることを示しますsの子供たち。fs − 1 [i] [j] f_ {s-1} [i] [j]fS - 1[ i ] [ j ]列挙は完全にスキップされますxsx_sバツSこのサブツリーの状況。コードは0− 10-1を模倣できます01バックパックの書き方は、ボリュームを大から小に循環させて、「それらの考慮グループ」の次元を節約することです。コードは次のように表示されます。

#include <iostream>
#include <cstring>
using namespace std;

const int N = 110, M = 2 * N;
int n, m;
int h[N], e[M], ne[M], w[M], idx;
int f[N][N];

void add(int a, int b, int c) {
    
    
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void dfs(int u, int parent) {
    
    
    for (int i = h[u]; i != -1; i = ne[i]) {
    
    
        int v = e[i];
        if (v == parent) continue;
        
        // 先递归求解f[v]
        dfs(v, u);

		// 枚举树枝总数的上界(即保留不超过多少个树枝)
        for (int j = m; j >= 1; j--) 
        	// 枚举v这棵子树取多少个树枝
            for (int k = 0; k < j; k++)
                f[u][j] = max(f[u][j], f[u][j - k - 1] + f[v][k] + w[i]);
    }
}

int main() {
    
    
    cin >> n >> m;

    memset(h, -1, sizeof h);
    for (int i = 0; i < n - 1; i++) {
    
    
        int a, b, c;
        cin >> a >> b >> c;
        // 只知道树根但不知道边的方向,所以只能建双向边
        add(a, b, c), add(b, a, c);
    }

    dfs(1, -1);

    cout << f[1][m] << endl;

    return 0;
}

時間と空間の複雑さO(NQ)O(NQ)O N Q

おすすめ

転載: blog.csdn.net/qq_46105170/article/details/114773793