您的位置:首页 > 其它

zoj 3211 砍树 有顺序的dp

2013-03-22 14:35 295 查看
zoj 3211

有n棵树,m天,每天只能砍一棵树,每棵树的初始价值为ai,每过一天价值增长bi,求m天砍树得到的最大价值。

开始贪心不可以,n棵树长m天好像可以分成n*m棵树再分组背包(一棵树只能砍一次)(装酒问题),dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+w[i]),但是一天有只能砍一棵树,有两个限制条件,直接背包有后效性,(放第i棵树可能改变dp[i-1][j]的值,即前面的状态不能保证是最终的状态) 不行。

n棵树,可以砍m天,就是n棵树中砍了m棵,那么应如何安排砍这m棵树的先后呢?显然m棵全砍掉,a1……am全部得到,考虑价值的增量,要按b的升序依次来砍才能使总和最大,这是高中数学不等式选讲里的一个什么不等式,大数乘大数相应的和最大。先将树按照b来升序排列,这样来保证每一组dp[i][j]中的j棵树的价值都是按照天数*b递增的来计算,当前第i棵树的b最大,也就不可能再放在j天前了,这样每次的dp[i-1][j]就是最优的结果,既然每个j棵树的顺序能确定,接下来就是在n棵树里选m棵,再对树进行分组背包就没有问题了。

方程dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+w[i]),i j升序,dp[i][j]表示在前i棵树中j天的最大价值也就是i棵树中砍j棵

和hdu 3466类似,骄傲的商人那个,都是有带顺序的背包,要考虑背包问题的本质

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int dp[300][300];
struct node{
int a,b;
}s[300];
int cmp(const void*aa,const void*bb)
{
node*a=(node*)aa;
node*b=(node*)bb;
return a->b > b->b;
}
int max(int a,int b)
{
return a>b?a:b;
}
int n,m;
int main()
{
int i,j,k,l;
scanf("%d",&l);
while(l--)
{
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&s[i].a);
for(i=1;i<=n;i++)
scanf("%d",&s[i].b);
qsort(s+1,n,sizeof(s[0]),cmp);
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+s[i].a+s[i].b*(j-1));
}
}
printf("%d\n",dp
[m]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: