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
*/