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; }