POJ 1192 最優連通子集 詳解樹形DP

2021-09-01 19:06:16 字數 2591 閱讀 7832

題目描述:

[color=blue][size=medium][b][align=center]最優連通子集[/align][/b][/size][/color]

[color=blue][b]description[/b][/color]

眾所周知,我們可以通過直角座標系把平面上的任何乙個點p用乙個有序數對(x, y)來唯一表示,如果x, y都是整數,我們就把點p稱為整點,否則點p稱為非整點。我們把平面上所有整點構成的集合記為w。

定義1 兩個整點p1(x1, y1), p2(x2, y2),若|x1-x2| + |y1-y2| = 1,則稱p1, p2相鄰,記作p1~p2,否則稱p1, p2不相鄰。

定義 2 設點集s是w的乙個有限子集,即s = (n >= 1),其中pi(1 <= i <= n)屬於w,我們把s稱為整點集。

定義 3 設s是乙個整點集,若點r, t屬於s,且存在乙個有限的點序列q1, q2, ?, qk滿足:

1. qi屬於s(1 <= i <= k);

2. q1 = r, qk = t;

3. qi~qi + 1(1 <= i <= k-1),即qi與qi + 1相鄰;

4. 對於任何1 <= i < j <= k有qi ≠ qj;

我們則稱點r與點t在整點集s上連通,把點序列q1, q2,..., qk稱為整點集s中連線點r與點t的一條道路。

定義4 若整點集v滿足:對於v中的任何兩個整點,v中有且僅有一條連線這兩點的道路,則v稱為單整點集。

定義5 對於平面上的每乙個整點,我們可以賦予它乙個整數,作為該點的權,於是我們把乙個整點集中所有點的權的總和稱為該整點集的權和。

我們希望對於給定的乙個單整點集v,求出乙個v的最優連通子集b,滿足:

1. b是v的子集

2. 對於b中的任何兩個整點,在b中連通;

3. b是滿足條件(1)和(2)的所有整點集中權和最大的。

[color=blue][b]input[/b][/color]

第1行是乙個整數n(2 <= n <= 1000),表示單整點集v中點的個數;

以下n行中,第i行(1 <= i <= n)有三個整數,xi, yi, ci依次表示第i個點的橫座標,縱座標和權。同一行相鄰兩數之間用乙個空格分隔。-10^6 <= xi, yi <= 10^6;-100 <= ci <= 100。

[color=blue][b]output[/b][/color]

僅乙個整數,表示所求最優連通集的權和。

[color=blue][b]sample input[/b][/color]

50 0 -2

0 1 1

1 0 1

0 -1 1

-1 0 1

[color=blue][b]sample output[/b][/color]

2該問題可以轉化為求乙個樹中子樹的權重最大和,樹形dp問題

解法思想:dp問題就需要確定動態轉移方程,針對每個節點u,可以考慮兩種情況,即包含該節點和不包含該節點,設dp[u][0]為不包含,則有

[align=center]dp[u][0]=max}(v是u的孩子節點)[/align]

dp[u][1]為包含節點u,為保證連通性,需要加上子節點大於0的dp值,即

[align=center]if(dp[v][1]>0)dp[u][1]+=dp[v][1][/align]

**實現如下:

#include

#include "math.h"

#define n 1010

#define max(a,b) a>b?a:b

//其實是邊的定義

typedef struct nodenode;

int px[n],py[n],pc[n];

int pre[n];//總是存放以n點開始的第一條邊(可以理解為第一條)

node edge[2*n];

int visited[n];//記錄節點是否已訪問過

int dp[n][2];

int edge_num=0;//邊的編號

void add_edge(int u,int v)

void dfs(int s)

}}int main()

dfs(1);

printf("%d\n",max(dp[1][0],dp[1][1]));

}

以sample input為例,理解**處理流程:

由於(0,0)和其他四個點都相鄰,所以將新增8條邊,新增完之後,edge陣列的值為

(2,-1)、(1,-1)、(3,0)、(1,-1)、(4,2)、(1,-1)、(5,4)、(1,-1)

此時,pre[1]=6(即以節點0,0為起點的第一條邊是edge[6])

pre[2]=1(以節點0,1為起點的第一條邊是edge[1])

pre[3]=3(以節點1,0為起點的第一條邊是edge[3])

pre[4]=5(以節點0,-1為起點的第一條邊是edge[5])

pre[5]=7(以節點-1,0為起點的第一條邊是edge[7])

dfs(1):

從edge[6]開始遍歷四個相鄰節點,然後按照動態轉移方程計算dp[1][0]和dp[1][1]

POJ 1192最優連通子集

最優連通子集 題目的描述太繁瑣了。其實意思簡單,就是給定若干個點,如果兩個點之間的曼哈頓距離小於1,就連邊。然後就構成一顆樹,然後每個點都 有乙個權值,然後選取若干個點,使得權值和最大,並且點與點之前都連通。簡單的樹形dp,dp i 表示以i點為根的子樹並且選取i點時的最大權值。方程就很好寫,dp ...

poj 1192 最優連通子集 (樹形dp)

設dp u 0 為以u為根的子樹,子集中沒有u的最大權值,dp u 1 則表示子集中有u。如果子集中沒有u,那麼u的所有兒子中只能選乙個。如果子集中有u,那麼u的所有兒子要麼不選,要麼必須在子集中。狀態轉移方程 dp u 0 max dp u 0 max dp v 0 dp v 1 dp u 1 m...

POJ 1192 最優連通子集 動態規劃

題意 簡單點說就是給定一棵樹,每個節點都有乙個權值,現在要求求出這棵樹的乙個聯通的一枝使其權值最大。解法 設sum i 為包含i節點在內的一枝的最大權值和,那麼sum i val i max 0,sum j 其中 i,j 之間存在邊。當sum j 為負數時,對父親節點的貢獻就為0了。如下 inclu...