树形DP——POJ1947 and POJ2486

来源:互联网 发布:下载桌面软件 编辑:程序博客网 时间:2024/05/22 13:38
本文针对POJ上的2057、1947、2486、3140四道题目,谈一下个人对树形DP的理解,上面4题无法覆盖树形DP的所有形式,但也有一定的针对性,值得去做一做,思考一下:
树形DP中常常用到“背包思想”,1947和2486就是利用了“背包思想”,状态想好了,最后就是在填“背包”,某个节点的“背包”是用他们的子树的状态进行填充的。
  • POJ1947:状态dp[i][p]表示以节点i为根的树,持有p个节点需要摧毁的最少的公路,状态转移方程大体可以写为dp[i][p]=Min{dp[i][p],{dp[i][p-k]+dp[j][k]|j is a child of i}}
  • POJ2486:状态dp[i][k][0]表示有k步可以走的情况下,女主角回到i节点吃到的最大苹果数;dp[i][k][1]表示有k步可以周的情况下,女主角不一定回到i(可能在i的子树中停止)吃到的最大苹果数。状态转移方程大体可以写为三个(1)dp[i][k][0]=Max{dp[i][k][0],{dp[i][k-l-2][0]+dp[j][l][0]|j is a child of i}};(2)dp[i][k][1]=Max{dp[i][k][1],{dp[i][k-l-2][0]+dp[j][l][1]|j is a child of i}};(3)dp[i][k][1]=Max{dp[i][k][1],{dp[i][k-l-2][1]+dp[j][l][0]|j is a child of i}};
至于POJ2057,首先要将子树进行排序,然后计算子树的一个状态——知道Home不在此子树中所要走的最少的步数
至于POJ3140,就是一个水题

POJ1947 codes
#include<iostream>#include<string.h>using namespace std;#define SIZE 152int dp[SIZE][SIZE];int children[SIZE][SIZE];int parent[SIZE];int col[SIZE];int P;void dfs(int now){if(children[now][0]==0){dp[now][1]=0;return ;}dp[now][1]=0;for(int i=1;i<=children[now][0];i++){dfs(children[now][i]);for(int j=P;j>=1;j--){if(dp[now][j]!=-1){   for(int k =1;k<=P;k++)   if(dp[children[now][i]][k]!=-1 && j+k<=P &&   (dp[now][j+k]==-1 || dp[children[now][i]][k]+dp[now][j] < dp[now][j+k])){       dp[now][j+k] = dp[children[now][i]][k]+dp[now][j];   }dp[now][j]+=1;}}}}int main(){int N;scanf("%d%d",&N,&P);memset(dp,-1,sizeof(dp));memset(children,0,sizeof(children));memset(parent,-1,sizeof(parent));memset(col,-1,sizeof(col));for(int i=1;i<N;i++){int p,c;scanf("%d%d",&p,&c);parent[c]=p;children[p][++children[p][0]] = c;}int root = 0;for(int i=1;i<=N;i++)if(parent[i]==-1){root = i;break;}dfs(root);int res = -1;for(int i=1;i<=N;i++)if(dp[i][P]!=-1){   int tmp = 0;   if(parent[i]==-1) tmp = dp[i][P];   else tmp = dp[i][P]+1;   if(res==-1 || tmp < res)   res = tmp;}printf("%d\n",res);system("pause");}

POJ2486 codes
/*dp[i][j][0]:在i节点还可以走j步,又走回i节点得到的最大苹果数dp[i][j][1]:在i节点还可以走j步,不一定走回i节点得到的最大苹果数dp[i][j][0]的转移方程很简单,dp[i][j][1]的转移方程有两个,注意体会第二*/#include<iostream>#include<string.h>using namespace std;#define SIZE 105int children[SIZE][SIZE];int val[SIZE];int dp[SIZE][205][2];int N,K;#define _max(x,y) ((x)>(y)?(x):(y))void dfs(int now,int parent){for(int i=0;i<=K;i++)dp[now][i][0]=dp[now][i][1]=val[now];if(children[now][0]!=0){for(int i=1;i<=children[now][0];i++){int child = children[now][i];if(child == parent) continue;dfs(child,now);for(int k=K;k>=0;k--)for(int j=0;j<=k;j++){//dp[now][k+2][0]dp[now][k+2][0] = _max(dp[now][k+2][0],dp[now][k-j][0]+dp[child][j][0]);//dp[now][k+1][1]dp[now][k+1][1] = _max(dp[now][k+1][1],dp[now][k-j][0]+dp[child][j][1]);//dp[now][k+2][1]dp[now][k+2][1] = _max(dp[now][k+2][1],dp[now][k-j][1]+dp[child][j][0]);}}}}int main(){while(scanf("%d%d",&N,&K)!=EOF){for(int i=1;i<=N;i++)scanf("%d",&val[i]);memset(children,0,sizeof(children));for(int i=1;i<N;i++){    int from,to;scanf("%d%d",&from,&to);children[from][++children[from][0]] = to;children[to][++children[to][0]] = from;}memset(dp,0,sizeof(dp));dfs(1,-1);printf("%d\n",dp[1][K][1]);}}




原创粉丝点击