HDU 4616 Game(樹形dp,兩遍dfs)

題目鏈接:
HDU 4616 Game
題意:
給一個n 個節點和n1 條邊的樹。每個節點代表一個房間,每個房間都放有一個價值爲正的禮物,有的房間有陷阱,有的房間沒陷阱,最多可以經過C 個陷阱(第C 個陷阱時就應該停止),可以從任意的房間開始行走,每個房間只能走一次,求獲得的禮物的最大價值和?
數據範圍:n5104,1C3
分析:
dp[u][i] 表示從u 出發經過i 個陷阱可以獲得的最大價值,第一次dfs 記錄從u 的子樹得到的結果,第二遍dfs 得到從父親方向的到的結果,所以需要對每種dp[u][i] 記錄最大和次大,以及取得最大時的id[u]
兩遍dfs ,注意下細節就好了。
時間複雜度:O(nC)

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX_N = 50010;

int T, n, total, C;
ll value[MAX_N], dp[MAX_N][5][5];
int head[MAX_N], trap[MAX_N], id[MAX_N][5];

struct Edge {
    int v, next;
} edge[MAX_N * 2];

void AddEdge (int u, int v) 
{
    edge[total].v = v;
    edge[total].next = head[u];
    head[u] = total++;
}

void dfs_son(int u, int p)
{
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v, t = trap[u];
        if (v == p) continue;
        dfs_son(v, u);
        for (int j = 1; j <= C - t; ++j) {
            ll son = dp[v][j][0] + value[u];
            if (son > dp[u][j + t][0]) {
                dp[u][j + t][1] = dp[u][j + t][0];
                dp[u][j + t][0] = son;
                id[u][j + t] = v;
            } else if (son > dp[u][j + t][1]) {
                dp[u][j + t][1] = son;
            }
        }
    }
}

void dfs_father(int u, int p)
{
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].v, t = trap[edge[i].v];
        if (v == p) continue;
        for (int j = 1; j <= C - t; ++j) {
            ll father;
            if (id[u][j] == v) father = dp[u][j][1] + value[v];
            else father = dp[u][j][0] + value[v];

            if (father > dp[v][j + t][0]) {
                dp[v][j + t][1] = dp[v][j + t][0];
                dp[v][j + t][0] = father;
                id[v][j + t] = u;
            } else if (father > dp[v][j + t][1]) {
                dp[v][j + t][1] = father;
            }
        }
        dfs_father(v, u);
    }
}

int main()
{
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &C);
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; ++i) {
            scanf("%lld%d", &value[i], &trap[i]);
            for (int j = 1; j <= C; ++j) {
                dp[i][j][0] = value[i];
                id[i][j] = i;
            }
        }
        memset(head, -1, sizeof(head));
        total = 0;
        for (int i = 1; i < n; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            AddEdge(u, v);
            AddEdge(v, u);
        }
        dfs_son(0, -1);
        dfs_father(0, -1);

        ll ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = max(ans, dp[i][C][0]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
發佈了464 篇原創文章 · 獲贊 37 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章