bzoj4247 挂饰

来源:互联网 发布:志鸿优化设计教案 编辑:程序博客网 时间:2024/05/22 15:03

Description

JOI君有N个装在手机上的挂饰,编号为1…N。 JOI君可以将其中的一些装在手机上。
JOI君的挂饰有一些与众不同——其中的一些挂饰附有可以挂其他挂件的挂钩。每个挂件要么直接挂在手机上,要么挂在其他挂件的挂钩上。直接挂在手机上的挂件最多有1个。
此外,每个挂件有一个安装时会获得的喜悦值,用一个整数来表示。如果JOI君很讨厌某个挂饰,那么这个挂饰的喜悦值就是一个负数。
JOI君想要最大化所有挂饰的喜悦值之和。注意不必要将所有的挂钩都挂上挂饰,而且一个都不挂也是可以的。

Input

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

Output

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

Sample Input

50 42 -21 -10 10 3

Sample Output

5

HINT

将挂饰2直接挂在手机上,然后将挂饰1和挂饰5分别挂在挂饰2的两个挂钩上,可以获得最大喜悦值4-2+3=5。

1<=N<=2000
0<=Ai<=N(1<=i<=N)
-10^6<=Bi<=10^6(1<=i<=N)

Source

JOI 2013~2014 春季training合宿 竞技4 By PoPoQQQ

Key To Problem

这道题不是很难想,一般写出搜索就应该可以想出dp的方法。
首先需要按照挂钩的数量从大到小排一下序;
f[i][j]表示到第i个挂饰还剩j个挂钩的最大喜悦值之和;
令x=j-1+joi[i].a;
则f[i][x]=max(f[i-1][x],f[i-1][j]+joi[i].b);
当然还有很多细节的问题,但是我比较菜,很多东西都是一点点试出来的,具体为什么我也不太记得了,还是看代码吧

Code

#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>#define N 2010#define inf 0x3f3f3f3fusing namespace std;struct node{    int w,c;};node joi[N];int n;int f[N][N];int cmp(const void *x,const void *y){    if((*(node *)x).w!=(*(node *)y).w)        return (*(node *)y).w-(*(node *)x).w;    return (*(node *)x).c-(*(node *)y).c;}int main(){//  freopen("straps.in","r",stdin);//  freopen("straps.out","w",stdout);    cin>>n;    for(int i=1;i<=n;i++)        scanf("%d%d",&joi[i].w,&joi[i].c);    qsort(joi+1,n,sizeof(joi[0]),cmp);    for(int i=0;i<=n;i++)        for(int j=0;j<=n;j++)            f[i][j]=-inf;    f[0][1]=0;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=n;j++)        {            f[i][j]=max(f[i-1][j],f[i][j]);            if(f[i-1][j]==-inf)                continue;            int x=j-1+joi[i].w;            if(x>n)                x=n;            f[i][x]=max(max(f[i-1][x],f[i][x]),f[i-1][j]+joi[i].c);        }    }    int ans=-inf;    for(int i=0;i<=n;i++)        ans=max(ans,f[n][i]);    cout<<ans<<endl;    return 0;}
0 0