인근에 문제 해결 P3047 [USACO12FEB] 소 인근 소

인근에 문제 해결 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

추천

출처www.cnblogs.com/YuanqiQHFZ/p/11622361.html