51nod3176 挂饰

3176 挂饰

JOI君有N个挂饰,编号为1...N。 JOI君可以将其中的一些装在手机上。(2 <= N <= 2000)

JOI君的挂饰有一些与众不同——其中的一些挂饰附有可以挂其他挂件的挂钩。每个挂件要么直接挂在手机上,要么挂在其他挂件的挂钩上。直接挂在手机上的挂件最多有1个。

此外,每个挂件有一个安装时会获得的喜悦值,用一个整数来表示。如果JOI君很讨厌某个挂饰,那么这个挂饰的喜悦值就是一个负数。

JOI君想要最大化所有挂饰的喜悦值之和。注意不必将所有的挂钩都挂上挂饰,而且一个都不挂也是可以的。

输入

第一行一个整数N,代表挂饰的个数。
接下来N行,第i行(1<=i<=N)有两个空格分隔的整数Ai和Bi,表示挂饰i有Ai个挂钩,安装
后会获得Bi的喜悦值。

输出

输出一行一个整数,表示手机上连接的挂饰总和的最大值

数据范围

22% 2 <= N <= 15
35% 2 <= N <= 100
100% 2 <= N <= 2000

输入样例

5
0 4
2 -2
1 -1
0 1
0 3

输出样例

5

解析:

我们把物品分成四类:

1.有挂钩,装饰度非负

2.有挂钩,装饰度为负数

3.无挂钩,装饰度非负

4.无挂钩,装饰度为负数

显然,对于第一种物品,肯定是要选的,第四种物品肯定是不选的

那么对于二、三种情况我们应该怎么处理呢?

对于第二种,我们求出数组f[],其中f[i]表示安装后有ii个挂钩时的最大装饰度。这个用01背包来做就可以了。

对于第三个,如果我们现在可以选k件第二种类型的挂钩,我们会怎么选?贪心的想法告诉我们,因为a[i]都相等,所以肯定挑b[i]更大的前k个。所以就枚举剩余挂钩的数量k,这样f[k]就是在1,2中选出一些挂饰剩余k个挂钩的最大装饰度,再加上b[i]最大的前k个第三种挂饰的喜悦值即可。

放代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
struct h{
int k,t;
}x[2500];
int cmp(const h&a,const h&b)
{
return a.k>b.k;
}
int max(int a,int b)
{
return (a>b?a:b);
}
int f[2500][2500];
int pop,n,ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d %d",&x[i].k,&x[i].t) ;
sort(x+1,x+n+1,cmp);
memset(f,-210000000,sizeof(f));
f[0][1]=0;
for (int i=1;i<=n;i++)
for (int j=0;j<=n;j++)
f[i][j]=max(f[i-1][j],f[i-1][max(j-x[i].k,0)+1]+x[i].t);
ans=0; 
for (int i=0;i<=n;i++)
ans=max(ans,f[n][i]);
printf("%d",ans);
return 0;
}

おすすめ

転載: blog.csdn.net/ZCH1901/article/details/120518616