題目描述:
[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...