1. 程式人生 > >poj 2342 / hdu 1520 Anniversary party(樹形dp)

poj 2342 / hdu 1520 Anniversary party(樹形dp)

Anniversary party

Time Limit: 1000MS Memory Limit: 65536K

Description
There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests’ conviviality ratings.

Input
Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go N – 1 lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0

Output
Output should contain the maximal sum of guests’ ratings.
Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

Sample Output
5

樹形dp真.第一題。

經典樹形dp,題意就略過了。樹形dp通過這道題給我的第一印象是dp + dfs,這道題是標準的入門題,狀態轉移很簡單:

dp[u][1] += dp[v][0];
dp[u][0] += max(dp[v][0], dp[v][1]);

其中dp[u][0]為第u個人不參加可得的最大值,dp[u][0]為第u個人參加可得的最大值。v是u的下屬(表現在書上即為u的子節點)。

其他的實現細節我覺得看程式碼和下面的截圖懂得更快。

日常犯蠢記錄:
原本是想要對照題解好好學習樹形dp的大致框架寫法,誰曾想被自己帶跑偏了。博主參考的程式碼有一些小trick,但原博主完全沒有解釋(具體參考陣列版程式碼)!結果博主一開始用的vector建圖,用於記錄每個父節點的子節點,並把vector放在全域性位置,總是re,後來把vector放進main函式以後又變成wa,但當時實在是想不出來是為什麼。

最後實在沒辦法,把vector改成了“記錄每個子節點的父節點”的陣列才過(就是陣列版的ac程式碼啦)。

疑惑之餘,又用vector改回來,然後發現輸出變成了0…

如圖:u的第一次輸出為0
這裡寫圖片描述

直覺告訴我問題就在這裡……按照博主程式碼的寫法,直接把最後一個fa傳入dfs的實際值為0,由於只有father[5]的值是0(即5沒有上級),第二次遞迴時就會回到正常運算。但是vector的話就會炸……

博主太蠢了Orz

迅速改掉,果然過了(vector版本)。

father陣列版本:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#define M 6005
#define INF 0x3f3f3f3f

using namespace std;

int dp[M][2], father[M], N;
bool vis[M];

void dfs(int u)
{
    vis[u] = false;
    for(int i = 1; i <= N; i++)
    {
        if(vis[i] && father[i] == u)
        {
            dfs(i);
            dp[u][0] += max(dp[i][0], dp[i][1]);
            dp[u][1] += dp[i][0];
        }
    }
}

int main()
{
    while(~scanf("%d", &N))
    {
        memset(vis, true, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= N; i++)
        {
            scanf("%d", &dp[i][1]);
        }
        int son, fa;
        while(scanf("%d %d", &son, &fa) && (son + fa))
        {
            father[son] = fa;
        }
        dfs(fa);//等同於dfs(0),trick就在這裡
        printf("%d\n", max(dp[fa][1], dp[fa][0]));
    }
    return 0;
}

執行結果:
這裡寫圖片描述

vector版本:

include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#define M 6005
#define INF 0x3f3f3f3f

using namespace std;

int dp[M][2];//vis也去掉了

void dfs(int u, vector<int> *super)
{
    for(int i = 0; i < super[u].size(); i++)
    {
        int v = super[u][i];
        dfs(v, super);
        dp[u][0] += max(dp[v][0], dp[v][1]);
        dp[u][1] += dp[v][0];
    }
}

int main()
{
    int N;
    while(~scanf("%d", &N))
    {
        vector<int> super[M];
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= N; i++)
        {
            scanf("%d", &dp[i][1]);
        }
        int son, fa, rt = 1;
        while(scanf("%d %d", &son, &fa) && (son + fa))
        {
            super[fa].push_back(son);
            if(rt == son)//做了修改
            {
                rt = fa;
            }
        }
        dfs(rt, super);
        printf("%d\n", max(dp[rt][1], dp[rt][0]));
    }
    return 0;
}

執行結果:
這裡寫圖片描述
論hdu就是比你快系列:
這裡寫圖片描述