首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

POJ 2342 Anniversary Party:樹形 DP 最大獨立集權值和

     編輯:關於C++

題目大意

公司层级構成樹 (根為校長)。每個員工有歡樂度值 (可正負)。派對邀請名單要求:**不同時邀請員工及其直屬上司**。求最大歡樂度和。N ≤ 6000。

樹形 DP 狀態定義

  • `dp[u][0]`:不選 u 時,u 子樹內最大歡樂度和。
  • `dp[u][1]`:選 u 時,u 子樹內最大歡樂度和。

轉移方程

DFS 後序遍歷:

  • `dp[u][1] = val[u] + Σ dp[v][0]` (選 u,子節點 v 必不選)
  • `dp[u][0] = Σ max(dp[v][0], dp[v][1])` (不選 u,子節點 v 可選可不選)

答案 = `max(dp[root][0], dp[root][1])`。

代碼實現 (C++)

#include 
#include 
#include 
#include 
using namespace std;

const int MAXN = 6005;
vector G[MAXN];
int dp[MAXN][2], val[MAXN];
int n, root;
bool hasFather[MAXN];

void dfs(int u) {
    dp[u][1] = val[u];
    dp[u][0] = 0;
    for (int v : G[u]) {
        dfs(v);
        dp[u][1] += dp[v][0];
        dp[u][0] += max(dp[v][0], dp[v][1]);
    }
}

int main() {
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; i++) {
            G[i].clear();
            hasFather[i] = false;
        }
        for (int i = 1; i <= n; i++) scanf("%d", &val[i]);
        for (int i = 0; i < n-1; i++) {
            int L, K; scanf("%d%d", &L, &K);
            G[K].push_back(L); // K 是 L 的上司
            hasFather[L] = true;
        }
        root = 1;
        while (hasFather[root]) root++; // 找根
        dfs(root);
        printf("%d\n", max(dp[root][0], dp[root][1]));
    }
    return 0;
}

HDU 1524 版本差異 (hdu1520)

HDU 1520 數據更強,需用**鏈式前向星**存圖避免 vector 慢,並注意遞歸深度 (N=6000 可能棧溢出,建議改迭代或擴大棧)。邏輯完全相同。

關鍵點

  • 樹的根由「無父節點」確定。
  • 歡樂度可為負,DP 自然處理 (不選負值節點通常更優)。
  • 輸入以 EOF 結束,多測試用例。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved