AtCoder ABC 060 D Simple Knapsack

背包问题。

但 w 的范围是1e9 ,显然不能用DP。

考虑到限制 w1 ≤ wi ≤ w1 + 3,所以最多只会有四个不同的重量,统计每个重量的物品数,

然后枚举每个重量选多少个物品,选物品时显然要贪心地选最大的。

代码很丑,也不知道怎么优化

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 110;

int n,cnt;
ll W,mi,ans;
int cn[10];
ll val[10][maxn],w[maxn],cw[maxn],wei[10],v[maxn],pre[10][maxn];

bool cmp(ll a,ll b){
    return a>b;
}

ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }

int main(){
    mi = 1e9 + 7;
    ans = 0;
    n = read(),W = read(); 
    for(int i=1;i<=n;i++){
        w[i] = read(); cw[i] = w[i];
        mi = min(mi, w[i]);
        v[i] = read();
    }
    
    sort(cw+1,cw+1+n);
    
    for(int i = 1;i <= n;i++){
        if(cw[i] != cw[i-1]){
            wei[++cnt] = cw[i];
        }
    }
    
    for(int i=1;i<=n;i++){
        int nt = w[i]-mi+1;
        val[nt][++cn[nt]] = v[i];
    }
    
    for(int i=1;i<=cnt;i++){
        sort(val[i]+1,val[i]+1+cn[i],cmp);
    }
    
    for(int i=1 ;i <= cnt;i++){
        for(int j = 1 ;j<=cn[i]; j++){
            pre[i][j]=val[i][j];
            pre[i][j]+=pre[i][j-1];
        }
    }
    
    if(cnt==4){
        for(int i=0 ;i <= cn[1];i++){
            for( int j= 0;j <= cn[2] ;j++){
                for( int k=0 ;k <= cn[3] ;k++){
                    for(int p = 0; p <= cn[4] ; p++){
                        if(i*wei[1]+j*wei[2]+k*wei[3]+p*wei[4]<=W){
                            ans =max( pre[1][i] + pre[2][j] + pre[3][k] + pre[4][p],ans);
                        }
                        
                    }
                }
            }
        }
    }
        
    if(cnt==3){
        for(int i=0 ;i <= cn[1];i++){
            for( int j= 0;j <= cn[2] ;j++){
                for( int k=0 ;k <= cn[3] ;k++){
                    if(i*wei[1]+j*wei[2]+k*wei[3]<=W){
                        ans =max( pre[1][i] + pre[2][j] + pre[3][k],ans);
                    }
                }
            }
        }
    }
    
        
    if(cnt==2){
        for(int i=0 ;i <= cn[1];i++){
            for( int j= 0;j <= cn[2] ;j++){
                if(i*wei[1]+j*wei[2]<=W){
                    ans =max( pre[1][i] + pre[2][j] ,ans);    
                }
            }
        }
    }
    
    if(cnt==1){
        for(int i=0 ;i <= cn[1];i++){
            if(i*wei[1]<=W){
                ans =max( pre[1][i] ,ans);
            }
        }
    }
    
    printf("%lld\n",ans);
    
    return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/13416759.html