题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
题目大意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少?
解题思路:树形DP入门题。由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优。其实不然,有可能父节点和子节点都不选,而要选子孙节点。不过只要再往深点想下,就可以得出动态规划的解法。每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那我们只要从叶子节点往根结点不断更新dp[i][0]和dp[i][1]就可以了。
状态转移方程:dp[i[[1] = sum(dp[j][0]) (当前选了,子节点必定不能选,最优的情况是都不选,然后累加)
dp[i][0] = sum(max(dp[i][0],dp[i][1])) (当选不选,子节点可选可不选,找大的那个状态)
简单的树形DP入门题
分别用STL中的vector建了个有向图
然后又用结构体建了个无向图。
两个程序
#include<iostream> #include<vector> #include<cmath> #include<cstdio> using namespace std; #define MAXSIZE 6050 vector<int> vec[MAXSIZE]; int weight[MAXSIZE]; int f[MAXSIZE]; //每个节点的父节点 int d[MAXSIZE][2]; int num; //d[a][0]表示不选择该节点,d[a][1]表示选择该节点 void dfs(int a) //用来求解d[a][0]和d[a][i] { unsigned int i; unsigned int len=vec[a].size(); d[a][1]=weight[a]; for(i=0;i<len;i++) dfs(vec[a][i]); for(i=0;i<len;i++) { d[a][1]+=d[vec[a][i]][0]; d[a][0]+=max(d[vec[a][i]][0],d[vec[a][i]][1]); } } int main() { int i,a,b; //freopen("a.txt","r",stdin); while(scanf("%d",&num)!=EOF) { for(i=1;i<=num;i++) { scanf("%d",&weight[i]); vec[i].clear(); d[i][0]=d[i][1]=0; f[i]=-1;//初始化的时候都是没有父节点的 } while(scanf("%d%d",&a,&b),a+b) { f[a]=b; vec[b].push_back(a); } a=1; while(f[a]!=-1) a=f[a]; dfs(a); cout<<max(d[a][0],d[a][1])<<endl; } return 0; }
<pre name="code" class="cpp">//第二种方法,用结构体来构建无向图 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define MAXN 6050 struct node { int v; node* next; }*head[MAXN],tree[MAXN*2]; bool vis[MAXN]; int weight[MAXN]; int ptr,num; int d[MAXN][2]; void init() { ptr=1; memset(vis,false,sizeof(vis)); memset(head,NULL,sizeof(head)); } void addEdge(int a,int b) //该段是模块化编程 { //所有的关于树形DP问题采用无向图方式表示地 tree[ptr].v=b; //都是这样构造无向图的 tree[ptr].next=head[a]; //采用2个一维的数组表示的 head[a]=&tree[ptr++]; tree[ptr].v=a; tree[ptr].next=head[b]; head[b]=&tree[ptr++]; } void bfs(int root) { if(vis[root]) //记忆化搜索,vis[root]为true表示已经求过d[root] return ; vis[root]=true; d[root][1]=weight[root]; node* p=head[root]; while(p) { if(!vis[p->v]) //只有没访问过才求其值 { bfs(p->v); d[root][1]+=d[p->v][0]; d[root][0]+=max(d[p->v][0],d[p->v][1]); } p=p->next; } } int main() { int i,a,b; freopen("a.txt","r",stdin); while(scanf("%d",&num)!=EOF) { init(); for(i=1;i<=num;i++) scanf("%d",&weight[i]); while(scanf("%d%d",&a,&b),a+b) addEdge(a,b); bfs(1); printf("%d\n",max(d[1][0],d[1][1])); } }
树状DP入门
时间: 2024-10-12 13:32:39