[贪心][完全背包]JZOJ 6309 完全背包

Description

 

Input

Output

 

Sample Input

Sample 1:
2 15
3 2
5 3

Sample 2:
3 70
71 100
69 1
1 2
 

Sample Output

Sample 1:
10

Sample 2:
140
 
 

Data Constraint

分析

这题终于用到了当年我学背包的时候想到过的贪心思想了

首先有用的物品不超过100个,如果a相同只要b最大的

然后有引理:给定n个整数,其中任意整数的和一定为n的倍数

然后我们将物品的性价比排序,如果性价比相同要体积小一点的

然后我们考虑背包的一大部分空间用性价比最高的物品填充,那么填充多少呢?

引理:其他非性价比最高的物品的个数<性价比最高的物品体积

因为当上面的符号变成≥时,一定有一部分体积的和是性价比最高体积的倍数,用它替换不会变劣

所以就要填充$\left \lfloor \frac{m}{a_{best}} \right \rfloor -100$个性价比最高物品

剩下做完全背包即可

 

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef long long ll;
const int N=1e5+10;
struct Item {
    ll a,b;
}t[20*N];
int n,n1;
ll f[N],ans,lans,m;

bool CMP(Item a,Item b) {return a.b*b.a>b.b*a.a||a.b*b.a==b.b*a.a&&a.a<b.a;}

bool CMP1(Item a,Item b) {return a.a<b.a||a.a==b.a&&a.b<b.b;}

int main() {
    freopen("backpack.in","r",stdin);
    freopen("backpack.out","w",stdout);
    scanf("%d%lld",&n,&m);
    for (int i=1;i<=n;i++) scanf("%lld%lld",&t[i].a,&t[i].b);
    sort(t+1,t+n+1,CMP1);n1=n;n=0;
    for (int i=1;i<=n1;i++) if (t[i].a!=t[i+1].a) t[++n]=t[i];
    sort(t+1,t+n+1,CMP);
    if (m/t[1].a>=100ll) ans=(m/t[1].a-100ll)*t[1].b,m-=((m/t[1].a)-100ll)*t[1].a;
    for (int i=0;i<=m;i++)
        for (int j=1;j<=n;j++)
            if (i+t[j].a<=m) f[i+t[j].a]=max(f[i+t[j].a],f[i]+t[j].b);
    for (int i=0;i<=m;i++) lans=max(lans,f[i]);
    printf("%lld\n",ans+lans);
}
View Code

 

posted @ 2019-08-19 07:51  Vagari  阅读(183)  评论(0编辑  收藏  举报