码迷,mamicode.com
首页 > 其他好文 > 详细

杯子题解

时间:2020-11-19 12:49:31      阅读:14      评论:0      收藏:0      [点我收藏+]

标签:二维   需要   sizeof   nta   code   背包   node   ==   描述   

题目描述

重庆八中在\(80\)周年校庆的时候获捐\(n\)个杯子, 每个杯子有两个属性:一个是已装水量\(ai\),一个是可装水量\(bi\)\(ai <= bi\))。

从一个杯子向另一个杯子倒\(x\)单位体积的水需要花费的时间是\(x\)秒。 现在用\(n\) 个杯子中的\(k\)个来装所有的水, 求最小的\(k\), 以及最少花费的时间 \(t\)


第一行:一个正整数\(n(1 <= n <= 100)\),代表杯子的个数。

第二行:\(n\)个正整数\(a1, a2, a3, a4 , … an(1 <= ai <= 100)\)\(ai\)表示第i 个杯子已装水量。

第三行:\(n\)个正整数\(b1, b2, b3, b4 , … bn(1 <= bi <= 100)\),\(bi\)表示第\(i\)个杯子可装水量。

保证对于任意一个杯子,\(ai <= bi\)


思路

这道题就是一道二维背包问题。
我们可以预处理出\(k\)的值。

然后用\(DP\)来求出\(t\)。我们令\(f[i][j][k]\)表示处理到了第\(i\)个杯子,一共选了\(k\)个杯子,可装水为\(j\)时的最大装水量。

那我们的递推式为:

f[i][j][k]=max(f[i-1][j][k],f[i-1][j-a[i].bi][k-1]+a[i].ai);
//f[i-1][j][k]为不选这个杯子
//f[i-1][j-a[i].bi][k-1]+a[i].ai为选这个杯子

就像\(01\)背包一样,我们可以把\(i\)这一位给省掉。
递推式就变为:

f[j][k]=max(f[j][k],f[j-a[i].bi][k-1]+a[i].ai);

代码

#include <bits/stdc++.h>
using namespace std;
int n,sum,all_water,f[10005][105],ans,need;
struct node{ int ai,bi; }a[105];

bool cmp(const node &a,const node &b) {
    if(a.bi==b.bi) return a.ai>b.ai;
    return a.bi>b.bi;
}

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i].ai),sum+=a[i].ai;
    for(int i=1;i<=n;i++) scanf("%d",&a[i].bi),all_water+=a[i].bi;
    
    sort(a+1,a+n+1,cmp);
    int value=0;
    for(int i=1;i<=n;i++) {//求k
        value+=a[i].bi,need++;
        if(value>=sum) break;
    }
    
    memset(f,-0x3f,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=n;i++) {
        for(int j=all_water;j>=a[i].bi;j--) {
            for(int k=1;k<=need;k++)
                f[j][k]=max(f[j][k],f[j-a[i].bi][k-1]+a[i].ai);
        }
    }
    
    for(int i=sum;i<=all_water;i++) ans=max(ans,f[i][need]);
    
    printf("%d %d",need,sum-ans);
    return 0;
}

杯子题解

标签:二维   需要   sizeof   nta   code   背包   node   ==   描述   

原文地址:https://www.cnblogs.com/sxqn/p/13974060.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!