POJ 2342 Anniversary party
大概就是给你一棵树,每个点上有个权值,改点与改点的父节点不能都选,求选出来的点的权值之和最大值
方法:
dp[i][0]表示以i为根节点的树中不选i点的的最大权值和,dp[i][1]表示选i点的最大权值和
因为点i与儿子节点不能同时选,
所以
do[i][1]= sum( dp[j][0] )
dp[i][0]= sum( max (dp[j][1], dp[j][0])) //j为i的儿子节点
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define maxn 6006 int a[maxn], head[maxn], next[maxn]; int dp[maxn][2], n, h[maxn]; void dfs(int v) { // printf("%d\n", v); if(head[v]== -1) { dp[v][0]= 0; dp[v][1]= a[v]; } else{ int t1= 0, t0= 0; for(int i= head[v]; i!= -1; i= next[i]) { dfs(i); t1+= dp[i][0]; t0+= max(dp[i][1], dp[i][0]); } dp[v][1]= t1+ a[v]; dp[v][0]= t0; } // printf("%d %d %d\n", v, dp[v][1], dp[v][0]); } int main() { while(scanf("%d %d",&n, &a[1])!=EOF ) { for(int i= 2; i<= n; i++) scanf("%d",&a[i]); int son, fa; memset(head, -1, sizeof head); memset(h, 0, sizeof h); for(int i= 1; i<= n; i++) { scanf("%d %d",&son, &fa); h[son]= 1; next[son]= head[fa]; head[fa]= son; } int v; //根节点 for(int i= 1; i<= n; i++) if(!h[i]) { v= i; break; } dfs(v); printf("%d\n", max(dp[v][0], dp[v][1])); } return 0; }
hdu 1561 The more, The Better
题意:
给你一棵N个节点的树,书上的每个点都有一个权值W【i】,从树上选出M个点(选点规则:选某点之前,必须先选改点的父亲节点),求M个点权值和最大值
1<= M<=N<= 200
方法:
设dp[i][j]表示以i为根节点的子树中选取j个点的最大权值,那么dp[i][j]= max(dp[k1][j1] + dp[k2][j2] +..) 其中ki为i的子节点,j1+ j2+...= j-1
刚开始做的时候,我想到这里就不知道怎么做了,后面看了别人解题报告才想到,把求dp【i】【j】看成背包问题
ki表示第i个物品,ji表示这个物品选ji个, 所以我们可以把求dp[i][j] 看成n个物品,每个物品最多选j-1次的背包问题即可
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define maxn 222 int w[maxn], head[maxn], next[maxn], dp[maxn][maxn], d[maxn]; void dfs(int n, int m) { if(head[n]== -1 || m== 1) { for(int i= 1; i<= m; i++) dp[n][i]= w[n]; } else { for(int i= head[n]; i!= -1; i= next[i]) dfs(i, m-1); int d[maxn]; memset(d, 0, sizeof d); for(int i= head[n]; i!= -1; i= next[i]) for(int j= m-1; j>= 1; j--) for(int k= 0; k<= j; k++) d[j]= max(d[j], d[j-k] +dp[i][k]); //这里转化成背包问题 for(int i= 0; i<= m-1; i++) dp[n][i+1]= d[i]+ w[n]; } } int main() { int n, m; while(scanf("%d %d",&n,&m) && (n || m)) { memset(head, -1, sizeof head); memset(w, 0, sizeof w); memset(dp, 0, sizeof dp); int a; for(int i= 1; i<= n; i++) { scanf("%d %d",&a, &w[i]); next[i]= head[a]; head[a]= i; } dfs(0, m+1); printf("%d\n",dp[0][m+1]); } return 0; }
wikioi 1163 访问艺术馆
题目链接:
http://codevs.cn/problem/1163/
感觉有点类似上题,不过比上题要简单
代码:
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <stack> using namespace std; #define maxn 111 int t[maxn], v[maxn], head[maxn], next[maxn], dp[maxn][666]; stack<int>s; void dfs(int n, int m) { if(v[n]) { for(int i= 2*t[n]; i<= m; i++) dp[n][i]= min((i- 2*t[n])/5, v[n]); } else { int aa= head[n]; int bb= next[aa]; if(m>= 2*t[n]) { dfs(aa, m- 2*t[n]); dfs(bb, m- 2*t[n]); } for(int i= 0; i<= m- 2*t[n]; i++) for(int j= 0; j<= i; j++) dp[n][i+ 2*t[n]]= max(dp[n][i+ 2*t[n]], dp[aa][j]+ dp[bb][i-j]); } } int main() { int time; scanf("%d",&time); scanf("%d %d",&t[1], &v[1]); if(!v[1]) { s.push(1); s.push(1); } int tot= 1; memset(head, -1, sizeof head); while(!s.empty()) { tot++; scanf("%d %d",&t[tot], &v[tot]); int f= s.top(); s.pop(); next[tot]= head[f]; head[f]= tot; if(!v[tot]) { s.push(tot); s.push(tot); } } dfs(1, time); printf("%d\n", dp[1][time]); return 0; }
hdu 1011 Starship Troopers
感觉和上上题差不多啊, 不过这题有个大坑啊 就是m=0 的时候, 原来是要输出0的,就算后面有花费为0的点也不能走
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; int dp[111][111], head[111], next[111], a[111], b[111]; void dfs(int n, int m) { if(!m) return;// 此处时为了保证m=0的时候结果为0 int MIN= a[n]/ 20; if(a[n]%20) MIN++; if(head[n]== -1) //叶子节点 { for(int i= MIN; i<= m; i++) dp[n][i]= b[n]; } else { int mm= m- MIN; if(mm>= 0) { for(int i= head[n]; i!= -1; i= next[i]) dfs(i, mm); int d[111]; memset(d, 0, sizeof d); for(int i= head[n]; i!= -1; i= next[i]) for(int j= mm; j>= 1; j--) for(int k= 1; k<= j; k++) d[j]= max(d[j], d[j-k]+ dp[i][k]); for(int i= 0; i<= mm; i++) dp[n][i+MIN]= d[i] + b[n]; } } } int main() { int n, m; while(scanf("%d %d",&n,&m) && (n!= -1 || m!= -1)) { for(int i= 1; i<= n; i++) scanf("%d %d",&a[i], &b[i]); memset(head, -1, sizeof head); int f, son; for(int i= 1; i<= n-1; i++) { scanf("%d %d",&f, &son); if(f> son) { int temp= f; f= son; son= temp; } next[son]= head[f]; head[f]= son; } memset(dp, 0, sizeof dp); dfs(1, m); printf("%d\n",dp[1][m]); } return 0; } /* 1 0 0 7 2 0 0 10 0 10 2 1 */