ZOJ 3956 Course Selection System [01背包]

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3956

题意:就是给你Hi,Ci的值,问怎么取使得下面那个式子的值最大:

  $$(sum_{i=1}^{m} H_{x_i})^2-(sum_{i=1}^{m} H_{x_i})	imes(sum_{i=1}^{m} C_{x_i})-(sum_{i=1}^{m} C_{x_i})^2$$

理解:当时做了好久以为是贪心>_<.后来看别人的题解发现是01背包,现在学了01背包以后看就好理解多了。

因为每个值都是取或不取,所以容易想到是01背包。而且Hi的范围是[1,10000],Ci的范围是[1,100],n是[1,500],所以明显可以发现Ci适合做“物品体积”,Hi做“物品价值”,ΣCi做背包容量。由上式可知,若使式子的值越大,则ΣHxi越大越好,那么就01背包后判断一下就好。

这个背包想法很灵活,我刚开始就没明白为啥把Hi当做容量进行01背包。现在想想应该就是根据式子能得出ΣHxi越大越好,那么就需要用一种办法求得在条件内使得ΣHxi尽量最大化,所以想到01背包,把Hxi当做价值,那么自然ΣCi就应该当做背包容量,Ci当做体积,从数据范围也能看出这一点。背包完了之后,就依次判断当前容量为i(此时获得ΣHxi为f[i])时求得的上式的值,取个最大的就好。

参考代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1000005;
ll f[maxn];
int c[505],h[505];
int n;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        memset(f,0,sizeof(f));
        scanf("%d",&n);
        ll sum=0;
        for (int i=1;i<=n;i++){
            scanf("%d%d",&h[i],&c[i]);
            sum+=c[i];//每次累加c[i],求得总共的背包容量
        }

        for (int i=1;i<=n;i++){
            for (int j=sum;j>=c[i];j--){
                f[j]=max(f[j],f[j-c[i]]+h[i]);//一维滚动数组优化空间,求当前容量能装多少Hi。
            }
        }

        ll ans=0;
        for (int i=1;i<=sum;i++){
            ans=max(ans,f[i]*f[i]-f[i]*i-i*i);//求容量为i(ΣCxi),装了f[j](ΣHxi)这么多Hi时,式子的最大值。
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zxhyxiao/p/6937168.html