인근에 문제 해결 P3047 [USACO12FEB] 소 인근 소
효과에 따라가, 각 노드의 난에 대해 당신에게 나무를 제공하는 것입니다 K의 범위 내에서 점의 권리를 획득하고
t 날아 확실히 폭력의 범위를 알고 데이터 봐, 그래서 우리는 (DFS를 작성하는 데 사용되는 코드) DP하는 방법을 고려해야합니다
우리는 다음 두 가지에 도달하기 전 케이 단계 도보 포인트 지점을 찾을 것에 대해 신중하게 생각
(a 점 제가 아래) 서브 트리 I 1.
2. 후 난의 아버지 (내가 아래에서 위로 포인트)
이 문제는 일반적으로 사용할 수있는 DFS 두 번 해결
우리는 F [I] [J]의 상태를 정의하는 전 단계의 범위 내의 점의 오른쪽과, (D)를 [I] [j]가 나는 걸어 점을 나타내고, 점 J 및 오른쪽의 범위 단계 엎드려 점 A J를 나타낸다.
라인에 - 우선 모든 DFS F [N] [K]를 결정 이것은 [U] [K] + = [V] [1 J] F F를 그 아들 노드들 U 및 V를 위해 상대적으로 간단하다. (첫 번째 알려진 리프 노드 DFS는 아버지 노드를 밀어)
우리는 DFS 2 어레이는 아들 (V)에 대해, U를 배열 (F)를 밀어 결정된 D 및 U는 D는 [V] + = (d [U] [K - 1] - [K] F [V] [K를 - 2]), 테이블 아래에 배열 범위에주의를 지불하지 않습니다. D [I] [J]가 루트 D [I] [J] [i]는 [J]를 f로 초기 값 F [I] [J]에 할당된다. (그의 아들 노드를 밀어 아버지 알려진 두 번째 노드 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 질문의 종류, 각 노드 아버지와 아들이 노드에 대한 답이 관련되어 우리가 두 개의 DFS에서 답을 찾을 수있는이 시간이, DFS는이 두 가지의 일반적인 순서를 용이하게합니다. 이 나무는 매우 깊은 이해와 달성 할 수있는 능력을 가지고 통과 할 필요하지만 아이디어는 실제로 그렇게 어렵지 않다.
19.08.31