近くの問題を解決P3047 [USACO12FEB]牛近所の牛

近くの問題を解決P3047 [USACO12FEB]牛近所の牛

トピックリンク

効果の対象とあなたのツリーを与えることです、各ノードiについて、kの範囲内のポイントの権利を取得し、

確かにtが飛ぶだろう暴力の範囲を知るために、データを見て、私たちは(DFSを書くために使用されるコードを)DPする方法を検討する必要があります

私たちは、私はK-ステップの散歩を、次の二つに到達するためのポイント・ポイントを見つけるかについて慎重に考えて

私は、(iダウンポイントによって)サブツリーで1

2.後、私の父(私は下から上にポイント)

この問題は、一般的に使用することができDFS二回解きます

私たちは、F [i] [j]の状態を定義し、私はステップの範囲内の点の右側と、dは[i] [j]は、私が歩くのポイントを示し、ポイントjと右の範囲内のステップダウンダウンJ点を表しています。

ライン上で - まず、すべてのDFS F [N] [k]を決定し、これは、[U] [K] + = [V] [1 J] F F、その子ノードUおよびVのための、比較的単純です。(最初に知られているリーフノードのDFSは、父ノードをプッシュ)

[V] [K F - 我々は、UとU、V息子のために、D [v] [K] + =(D [U] [ - 1 k]は、DFS二番目の配列は、Fアレイを押すと判定されたdは - 2])、テーブルの下に配列の境界に注意を払っていません。D [i]は[j]は、ルートD [i]は[J] [I] [j]はFであり、初期値f [i]は[J]に割り当てられます。(彼の息子のノードを押して父を知られている第2のノードDFS)

アイデアは、それが少しくどいかもしれ入れますコードそれを見てください:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
#define N 100005
using namespace std;
inline int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
    while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

ll f[N][25], d[N][25];
//f数组和d数组前面已经说了
int val[N];
int n, k, tot, head[N];

struct edge
{
    int to, next;
    edge() {}
    edge(int x, int y) { to = x; next = y; }
}a[N * 2];
//邻接表存图
void add(int from, int to)
{
    a[++tot] = edge(to, head[from]);
    head[from] = tot;
}

void dfs(int x, int fa)
{
    for (int i = 0; i <= k; i++) f[x][i] = val[x];
    for (int i = head[x]; i; i = a[i].next)
    {
        int u = a[i].to;
        if (u != fa)
        {
            dfs(u, x);//先dfs到叶子节点,然后推父亲节点
            for (int i = 1; i <= k; i++)
                f[x][i] += f[u][i - 1];
        }
    }
}
//第一次dfs
void dfs2(int x, int fa)
{
    for (int i = head[x]; i; i = a[i].next)
    {
        int u = a[i].to;
        if (u != fa)
        {
            d[u][1] += f[x][0];
            for (int i = 2; i <= k; i++)
                d[u][i] += d[x][i - 1] - f[u][i - 2];
            dfs2(u, x);//先dfs父亲节点,更新完儿子后dfs儿子
        }
    }
}
//第二次dfs
int main()
{
    n = read(), k = read();
    for (int i = 1; i < n; i++)
    {
        int a1 = read(), a2 = read();
        add(a1, a2);
        add(a2, a1);
    }
    for (int i = 1; i <= n; i++)
        val[i] = read();
    dfs(1, 1);
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= k; j++)
            d[i][j] = f[i][j];//把f赋给d
    dfs2(1, 1);
    for (int i = 1; i <= n; i++)
        cout << d[i][k] << endl;//输出答案
    return 0;
}

とにかく、私は、木のDPの質問の種類は、各ノードの父と息子のこのノードへの答えが関連している私たちは2つのDFSで答えを見つけることができます。この時間を持って、DFSは、これら二つの異なる一般的な順序を促進します。これは、ツリーは非常に深い理解と達成する能力を持っているトラバースする必要がありますが、アイデアは、実際にはそれほど難しいことではありません。

19.08.31

おすすめ

転載: www.cnblogs.com/YuanqiQHFZ/p/11622361.html