近くの問題を解決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