POJ1192最優連通子集(樹狀dp)
阿新 • • 發佈:2019-02-07
最優連通子集
定義1 兩個整點P1(x1, y1), P2(x2, y2),若|x1-x2| + |y1-y2| = 1,則稱P1, P2相鄰,記作P1~P2,否則稱P1, P2不相鄰。
定義 2 設點集S是W的一個有限子集,即S = {P1, P2,..., Pn}(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)的所有整點集中權和最大的。
第1行是一個整數N(2 <= N <= 1000),表示單整點集V中點的個數;
以下N行中,第i行(1 <= i <= N)有三個整數,Xi, Yi, Ci依次表示第i個點的橫座標,縱座標和權。同一行相鄰兩數之間用一個空格分隔。-10^6 <= Xi, Yi <= 10^6;-100 <= Ci <= 100。
Time Limit: 1000MS | Memory Limit: 10000K |
Total Submissions: 2140 | Accepted: 1139 |
Description
眾所周知,我們可以通過直角座標系把平面上的任何一個點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 = {P1, P2,..., Pn}(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)的所有整點集中權和最大的。
Input
以下N行中,第i行(1 <= i <= N)有三個整數,Xi, Yi, Ci依次表示第i個點的橫座標,縱座標和權。同一行相鄰兩數之間用一個空格分隔。-10^6 <= Xi, Yi <= 10^6;-100 <= Ci <= 100。
Output
僅一個整數,表示所求最優連通集的權和。Sample Input
50 0 -20 1 11 0 10 -1 1-1 0 1Sample Output
2
分析: 這題的意思是求一個連通圖,並要求這個圖的擁有最大權。 用的是樹狀DP,用DFS深搜,DP[u][0]表示以u為根且不含u的最大值,Dp[u][1]表示以u為根且含有u的最大值; 程式碼: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int MAXN = 1010; int ABS(int x) { return x > 0 ? x : -x; } struct Node { int to,next; }; Node n[MAXN<<1]; int index = 0; int head[MAXN]; void make_map(int from,int to) { n[index].to = to; n[index].next = head[from]; head[from] = index++; } void makemap(int from,int to) { make_map(from,to); make_map(to,from); } int X[MAXN],Y[MAXN],C[MAXN]; int N; int vis[MAXN],dp[MAXN][2]; void DFS(int u) { vis[u] = 1; dp[u][0] = 0;dp[u][1] = C[u]; for(int i = head[u];~i;i=n[i].next) { int v = n[i].to; if(!vis[v]) { DFS(v); dp[u][0] = max(dp[u][0],max(dp[v][0],dp[v][1])); //將無根與其子孫比較。 if(dp[v][1]>0) dp[u][1] += dp[v][1]; } } } int main() { while(scanf("%d",&N)!=EOF) { for(int i = 1;i <= N;i++) { scanf("%d%d%d",&X[i],&Y[i],&C[i]); } index=0; memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); for(int i = 1;i <= N;i++) { for(int j = i+1;j <= N;j++) { if(1 == ABS(X[i]-X[j]) + ABS(Y[i]-Y[j])) { makemap(i,j); } } } DFS(1); printf("%d\n",max(dp[1][0],dp[1][1])); } return 0; }