BZOJ4247_挂饰_KEY

题目传送门

背包的变形,不得不说卡了我很久(估计是下午睡傻了)。

设f[i][j]为前i个物品剩下j个挂钩。

f[i][j]=max(f[i-1][j],f[i-1][max(j-a[i].x,0)+1]);

显然f[i-1][j]表示不挂,而f[i-1][max(j-a[i].x,0)+1]表示挂。

第二个之所以+1是因为原本就有一个钩子。j-a[i].x表示转移前的钩子数量。

有一点很重要,那就是要对钩子数量从大到小排列,不然的话会产生后效性。

因为如果钩子多的在钩子少的后面,那么两者就可以对换。

code:

/**************************************************************
    Problem: 4247
    User: yekehe
    Language: C++
    Result: Accepted
    Time:2728 ms
    Memory:17516 kb
****************************************************************/
 
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
 
char tc()
{
    static char fl[1000000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,1000000,stdin),A==B)?EOF:*A++;
}
 
int read()
{
    char c;while(c=tc(),(c<'0'||c>'9')&&c!='-');
    int x=0,y=1;c=='-'?y=-1:x=c-'0';
    while(c=tc(),c>='0'&&c<='9')x=x*10+c-'0';
    return x*y;
}
 
const int MAXN=2005;
int N,f[MAXN][MAXN];
struct node{
    int x,y;
}a[MAXN];
int cmp(node x,node y){return x.x>y.x;}
 
int main()
{
//  freopen("x.txt","r",stdin);
    N=read();
        for(int i=1;i<=N;i++)a[i].x=read(),a[i].y=read();
    memset(f,-63,sizeof(f));
    sort(a+1,a+N+1,cmp);
    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(0,j-a[i].x)+1]+a[i].y);
    int ans=0;
        for(int i=0;i<=N;i++)ans=max(f[N][i],ans);
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-01-17 16:48  Cptraser  阅读(109)  评论(0编辑  收藏  举报