题目描述

蛤布斯有nn个物品和一个大小为mm的背包,每个物品有大小和价值,它希望你帮它求出背包里最多能放下多少价值的物品。

输入数据

第一行两个整数 n,mn,m。

接下来 nn 行每行两个整数 xiwixi,wi,表示第ii个物品的大小和价值。

输出数据

一行一个整数表示最大价值。

样例输入

5 100
95 80
4 18
3 11
99 100
2 10

样例输出

101

数据范围

对于20%20%的数据,xi1500xi≤1500。

对于30%30%的数据,wi1500wi≤1500。

对于100%100%的数据,n40,0m1018,0xi,wi1016n≤40,0≤m≤1018,0≤xi,wi≤1016。

题目分析

整体二分啊,我先打了个DP,结果很悲壮。因为题目的数据太大了,m到long long极限了,所以用整体二分。整体二分是什么呢?我们枚举左半边,并排序。然后对右边进行搜索。这就是折半搜索。然后我们上代码。20分做法就是直接DP滚动数组。

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct aa{int v,w;
    friend bool operator<(aa a,aa b){
        return a.v!=b.v?a.v<b.v:a.w>b.w;
}}b[1<<21];
int n,cnt,tot,n2,m,v[50],w[50],ans;
inline int search(int x){
    int l=1,r=tot,mid;
    while(l<r){
        if(b[mid=(l+r)>>1].v>x)r=mid;
        else l=mid+1;
    }return b[l-1].w;
}void dfs1(int now,int sum_v ,int sum_w){
    if(now>n2){b[++cnt]=(aa){sum_v,sum_w};return;}
    dfs1(now+1,sum_v,sum_w);
    if(sum_v+v[now]<=m)    dfs1(now+1,sum_v+v[now],sum_w+w[now]);
}void dfs2(int now,int sum_v,int sum_w){
    if(now>n){
        ans=max(ans,sum_w+=search(m-sum_v));
        return;
    }dfs2(now+1,sum_v,sum_w);
    if(sum_v+v[now]<=m)    dfs2(now+1,sum_v+v[now],sum_w+w[now]);
}signed main(){freopen("pack.in","r",stdin),freopen("pack.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)    cin>>v[i]>>w[i];
    n2=n>>1,dfs1(1,0,0),sort(b+1,b+cnt+1);
    for(int i=2;i<=cnt;i++)
        if(b[i].v>b[i-1].v) b[++tot]=b[i];
    for(int i=2;i<=tot;i++) b[i].w=max(b[i].w,b[i-1].w);
    dfs2(n2+1,0,0),cout<<ans;
}

代码说明

我家小姐姐没什么信心,我也没什么期望了。到时候生物信息两开花。说多了都是泪,最近没什么心情更新我们的情感生活了。

posted on 2019-04-03 19:26  aserrrre  阅读(88)  评论(0编辑  收藏  举报