藍橋杯-算法訓練--ALGO-4 結點選擇


 本人是一個剛剛接觸C++不久的傻學生~記錄一些自己的學習過程。大神路過可以批評指正~

剛學動態規划,水平還很渣,一下子不知道從何下手,借鑒了一下這位大哥的文章

http://www.cnblogs.com/yifan2016/p/5268887.html

 

 

問題描述

有一棵 n 個節點的樹,樹上每個節點都有一個正整數權值。如果一個點被選擇了,那么在樹上和它相鄰的點都不能被選擇。求選出的點的權值和最大是多少?

輸入格式

第一行包含一個整數 n 。

接下來的一行包含 n 個正整數,第 i 個正整數代表點 i 的權值。

接下來一共 n-1 行,每行描述樹上的一條邊。

輸出格式
輸出一個整數,代表選出的點的權值和的最大值。
樣例輸入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
樣例輸出
12
樣例說明
選擇3、4、5號點,權值和為 3+4+5 = 12 。
數據規模與約定

對於20%的數據, n <= 20。

對於50%的數據, n <= 1000。

對於100%的數據, n <= 100000。

權值均為不超過1000的正整數。

 

 

解題:

一道基本的樹形動態規划題目。

dp[x][0]表示x結點不選中時最大的權值,dp[x][1]表示x結點選中時最大的權值

狀態轉移方程:dp[x][1] = dp[x][1] + dp[u][0]  (u為x的子結點)

       dp[x][0] = dp[x][0] + max{dp[u][0],dp[u][1]}(u為x的子結點)

代碼如下:

 

 

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;    
#define max(a,b) a>b?a:b
const int MAXN = 100001;
int M;     //表示邊的索引號,初始為0
int head[MAXN];      //表示某個結點所連接的邊
int dp[MAXN][2];     //dp[x][0]表示第x個結點不選擇時最大權值,dp[x][1]表示第x個結點選擇時最大權值
struct Edge{
    int toNode;      //表示這條邊到達的結點
    int nextEdge;   //表示這條邊的出發結點連接的下一條邊
}edge[2*MAXN];        //一共有n個結點,有n-1條邊,但是不同的出發結點算作不同的邊,所以有2n-2條邊

//把新邊加入邊集,構造樹
void add(int from, int to){
    edge[M].toNode = to;
    edge[M].nextEdge = head[from];
    head[from] = M++;                            //head[x]的值可能會被二次賦值
}

//類似dfs遍歷
void dfs(int node, int preNode){
    for (int i = head[node]; i != -1; i = edge[i].nextEdge){
        if (edge[i].toNode == preNode)             //說明這條邊已經搜索過
            continue;
        int toNode = edge[i].toNode;           //表示邊i到達的結點
        dfs(toNode, node);
        dp[node][0] += max(dp[toNode][0], dp[toNode][1]);             //該結點不算,則該邊上的另一結點可選也可不選
        dp[node][1] += dp[toNode][0];                                  //改結點選了,該邊上另一結點就不能選了
    }
}
int main(){
    int n;
    memset(head, -1, sizeof(head));           //所有邊置為-1,表示不存在該邊
    memset(dp, 0, sizeof(dp));
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> dp[i][1];                      //每一個結點的權值
    }
    for (int j = 1; j <= n - 1; j++){
        int from, to;
        cin >> from >> to;
        add(from, to);              
        add(to, from);
    }
    dfs(1, 0);                      //從1號結點開始向后動態規划
    int result = max(dp[1][0], dp[1][1]);          //因為不確定根結點,所以從幾號開始動態規划就找幾號的狀態
                                                                //同樣這里也可以寫成      dfs(2, 0);   int result = max(dp[2][0], dp[2][1]);不過當只有一個結點的時候就不對了
    cout << result << endl;
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM