POJ1192 树形DP 最优连通子集

最优连通子集
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 1837   Accepted: 947

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

第1行是一个整数N(2 <= N <= 1000),表示单整点集V中点的个数;
以下N行中,第i行(1 <= i <= N)有三个整数,Xi, Yi, Ci依次表示第i个点的横坐标,纵坐标和权。同一行相邻两数之间用一个空格分隔。-10^6 <= Xi, Yi <= 10^6;-100 <= Ci <= 100。

Output

仅一个整数,表示所求最优连通集的权和。

Sample Input

5
0 0 -2
0 1 1
1 0 1
0 -1 1
-1 0 1

Sample Output

2

Source

自己写的第一道树形DP,表示从来DP都和我有仇...纠结了老久才明白怎么成了一个树了……
给定的是一颗树,根据题意,我们可以从任意一个节点出发,必能访问到其他所有节点,那么dp的起点可以在任意一个节点。我们从该起点出发,对以此点为根的树的每个分支进行搜索,采用树的后续遍历法则,对于每个子树来说,dp值首先加上根节点(因为要保证连通性,所以返回值中必须包含根节点的值,即使为负数也必须加上)先对每个分支dp,然后看分支dp的返回值是不是正数,如果是正数,那么我们就把该分支的返回值加入到该树中去。

就是每个子树的根节点(包括叶子节点)记录dp[i][0]与dp[i][1],前一个表示不包含根的最大值,后一个表示包含根的最大值。那么我们可以得到对于dp[i][0],必然是所有分支中dp[child][0]与dp[child][1]中大于0的最大值的累加(因为不包含树根,所以在根节点上的连通性不用保证),dp[i][1]必然是所有分支中dp[child][1]中大于0的最大值的累加再加上该树根本身的值(因为要保证连通性)。最后只要比较dp[root][0]与dp[root][1],输出较大。

View Code
 1 #include <stdio.h>
 2 #include <iostream>
 3 using namespace std;
 4 int Abs(int x)
 5 {
 6     return x>=0?x:-x;
 7 }
 8 int max(int x,int y,int z)
 9 {
10     if(x<y) x=y;
11     if(x<z) x=z;
12     return x;
13 }
14 int max(int x,int y)

15 {
16     return x>y?x:y;
17 }
18 struct P
19 {
20     int x,y,c;
21     void input()
22     {
23         scanf("%d%d%d",&x,&y,&c);
24     }
25     bool isConnect(P & t)
26     {
27         if(Abs(x-t.x)+Abs(y-t.y)==1) return 1;
28         return 0;
29     }
30 }p[1005];
31 struct Edge
32 {
33     int v,next;
34 }edge[10005];
35 int edgeNum,head[1005];
36 int dp[1005][2];
37 void addEdge(int u,int v)
38 {
39     edge[edgeNum].v=v;
40     edge[edgeNum].next=head[u];
41     head[u]=edgeNum++;

42 }
43 void dfs(int x,int father)
44 {
45     dp[x][0]=0;
46     dp[x][1]=p[x].c;
47     for(int i=head[x];i!=-1;i=edge[i].next)
48     {
49         if(edge[i].v!=father)
50         {
51             dfs(edge[i].v,x);
52             dp[x][0]=max(dp[x][0],dp[edge[i].v][0],dp[edge[i].v][1]);
53             if(dp[edge[i].v][1]>0)
54             {
55                 dp[x][1]+=dp[edge[i].v][1];
56             }
57         }
58     }
59 }
60 int main()
61 {
62     int n;
63     while(scanf("%d",&n)!=EOF)
64     {
65         for(int i=0;i<n;i++)
66         {
67             head[i]=-1;
68             p[i].input();
69         }
70         edgeNum=0;
71         for(int i=0;i<n;i++)
72           for(int j=i+1;j<n;j++)
73           {
74               if(p[i].isConnect(p[j]))
75               {
76                   addEdge(i,j);
77                   addEdge(j,i);
78               }
79           }
80         dfs(0,-1);
81         printf("%d\n",max(dp[0][0],dp[0][1]));
82     }
83 }


 

posted @ 2012-07-23 00:03  _sunshine  阅读(990)  评论(0)    收藏  举报