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)的所有整点集中权和最大的。
我们则称点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。
以下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 }


浙公网安备 33010602011771号