UVA - 10163 Storage Keepers 多重背包

问题

仓库守卫,一共有N个仓库,有M人应聘首位,每个仓库最多一个守卫,一个守卫可以看管多个仓库,守卫i的能力值是 P i P_i Pi,薪资等于能力值,仓库的安全系数L等于 P i / K P_i/K Pi/K的整数部分, K K K是守卫 i i i看守的仓库数量
求最小安全系数的最大值,和此前提下的最小能力值总和

分析

多重背包思路有点相似
分开计算,首先求最大最小安全系数 L(使用二分法或者DP),再求最小的能力值总和Y
状态:
L(i,j)代表为前i个守卫安排负责前j个仓库得到的最大最小安全系数
Y(i,j)代表为前i个守卫安排负责前j个仓库在符合要求的情况下(系数大于要求)得到的最小费用
状态转移方程是
L [ i ] [ j ] = m a x ( L [ i ] [ j ] , m i n ( v a l u e [ i ] / k , L [ i − 1 ] [ j − k ] ) ) , 0 < = k < = j L[i][j]=max(L[i][j],min(value[i]/k,L[i-1][j-k])),0<=k<=j L[i][j]=max(L[i][j],min(value[i]/k,L[i1][jk])),0<=k<=j
Y [ i ] [ j ] = m i n ( Y [ i ] [ j ] , v a l u e [ i ] + Y [ i − 1 ] [ j − k ] ) , 1 < = k < = j , a n s ∗ k < = v a l u e [ i ] Y[i][j]=min(Y[i][j],value[i]+Y[i-1][j-k]),1<=k<=j,ans*k<=value[i] Y[i][j]=min(Y[i][j],value[i]+Y[i1][jk]),1<=k<=j,ansk<=value[i]

#include<iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=105,maxm=35,Inf=0x3f3f3f3f;
int L[maxm][maxn],Y[maxm][maxn],N,M,p[maxn];  //L代表最大最小安全系数,Y代表此前提下的最小能力值总和

int main(void){
    for(int i=0;i<maxm;++i){
        L[i][0]=Inf;  //i人看守0个仓库
    }
    //N是仓库数量,M是应聘人数
    while(cin>>N>>M && N){
        for(int i=1;i<=M;++i) scanf("%d",&p[i]);
        for(int i=1;i<=M;++i){  //守卫
            for(int j=1;j<=N;++j){  //仓库
                L[i][j]=L[i-1][j];  //第i个守卫不雇佣
                for(int k=1;k<=j;++k){ //雇佣第i个守卫看守k个仓库
                    L[i][j]=max(L[i][j],min(p[i]/k,L[i-1][j-k]));
                }
            }
        }
        int ans=L[M][N];

        for(int i=1;i<=M;++i){
            for(int j=1;j<=N;++j){
                Y[i][j]=Inf;
                if(L[i][j]<ans) break;
                if(L[i-1][j]>=ans)
                    Y[i][j]=Y[i-1][j];  //第i个守卫不雇佣,费用不变
                for(int k=1;k<=j && ans*k<=p[i];++k){  //雇佣第i个守卫看守k个仓库
                    if(L[i-1][j-k]>=ans)
                        Y[i][j]=min(Y[i][j],p[i]+Y[i-1][j-k]);
                }
            }
        }
        printf("%d %d\n",ans,Y[M][N]);
    }
}

L [ j ] = m a x ( L [ j ] , m i n ( v a l u e [ i ] / k , L [ j − k ] ) ) , 0 < = k < = j L[j]=max(L[j],min(value[i]/k,L[j-k])),0<=k<=j L[j]=max(L[j],min(value[i]/k,L[jk])),0<=k<=j
Y [ j ] = m i n ( Y [ i ] [ j ] , v a l u e [ i ] + Y [ i − 1 ] [ j − k ] ) , 1 < = k < = j , a n s ∗ k < = v a l u e [ i ] Y[j]=min(Y[i][j],value[i]+Y[i-1][j-k]),1<=k<=j,ans*k<=value[i] Y[j]=min(Y[i][j],value[i]+Y[i1][jk]),1<=k<=j,ansk<=value[i]

#include<iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=105,maxm=35,Inf=0x3f3f3f3f;
int L[maxn],Y[maxn],N,M,p[maxn];  //L代表最大最小安全系数,Y代表此前提下的最小能力值总和

int main(void){
    //N是仓库数量,M是应聘人数
    while(cin>>N>>M && N){
        for(int i=1;i<=M;++i) scanf("%d",&p[i]);
        memset(L,0,sizeof(L));
        memset(Y,Inf,sizeof(Y));
        L[0]=Inf;
        for(int i=1;i<=M;++i){
            for(int j=N;j>=1;--j){
                for(int k=1;k<=j;++k){
                    L[j]=max(L[j],min(p[i]/k,L[j-k]));
                }
            }
        }
        int ans=L[N];
        if(ans==0){  //这种写法无法处理一个守卫都不选的情况,只能输出0
            printf("%d %d\n",ans,0);
            continue;
        }
        Y[0]=0;
        for(int i=1;i<=M;++i){
            for(int j=N;j>=1;--j){
                for(int k=1;k<=j && ans*k<=p[i];++k){
//                    if(Y[j-k]>=ans)
                    Y[j]=min(Y[j],p[i]+Y[j-k]);
                }
            }
        }
        printf("%d %d\n",ans,Y[N]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值