[CF 730J] Bottles

Description

Nick has \(n ( n \leq 100 )\) bottles of soda left after his birthday. Each bottle is described by two values: remaining amount of soda \(a_{i}\) and bottle volume \(b_{i} ( a_{i}\leq b_{i}\leq 100 )\).

Nick has decided to pour all remaining soda into minimal number of bottles, moreover he has to do it as soon as possible. Nick spends \(x\) seconds to pour \(x\) units of soda from one bottle to another.

Nick asks you to help him to determine \(k\) — the minimal number of bottles to store all remaining soda and \(t\) — the minimal time to pour soda into \(k\) bottles. A bottle can't store more soda than its volume. All remaining soda should be saved.

2016-2017 ACM-ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)

Solution

Steps

The first question is very easy to solve. We know if we pour all soda into the minimal number of bottles, we can use bottles as big as we have. So we can just sort them through the volume, and choose big bottles until they can store all remaining soda.

But the next question is not so easy to solve. What if we change the way to look at this problem? We can try to use the method like what we have ever used in 0/1 knapsack problem. But how to deal with the problem like 0/1 knapsack problem? Remember, we should change the way!

In this problem, the bottles' volume is not the knapsack's volume but the 'cost' of elements. How about soda which will cost the time? It should be the 'volume' of the knapsack! Why should we do this?

As you know, in the 0/1 knapsack problem, we should just choose some elements. But if we make soda( time ) be the elements, we should choose all bottles. If we choose all of them, this solution will not be changed in another way — we can still not solve this problem. If we change it in another way, the only difference between 0/1 knapsack problem and this problem is that the volume is not stationary. Before we solve this little question, we should get the DP formual. The DP array (f[i][k][j]) we will use means when we consider the \(i\)th bottle the maximum volume formed by first k bottles whose volume is at most j. The formula of DP is here:

\[f[i][k][j] = \max (f[i][k][j], f[i-1][k-1][j-a[i]] + b[i])\; j\leq \sum a[i], k\leq i\]

While we get the biggest volume of \(k\) bottles (the volume must bigger than all soda's volume), we should find the most soda the bottles have. Because when we pour the soda into these bottles, the \(t\) will be the minimal.

And now it's time to show my code.

Code

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

struct bottle
{
    int v, w;
}bot[105];

int f[105][10005], totw, totv;
//the first dimension can be removed.

bool cmp(const bottle a, const bottle b)
{
    return a.v > b.v;
}

int main()
{
    int n;
    scanf("%d", &n);
    for(register int i = 1; i <= n; i += 1)
        scanf("%d", &bot[i].w), totw += bot[i].w;
    for(register int i = 1; i <= n; i += 1)
        scanf("%d", &bot[i].v);
    int K = 0;
    sort(bot+1, bot+n+1, cmp);
    for(register int i = 1; i <= n; i += 1)
    {
        totv += bot[i].v;
        if(totv >= totw)
        {
            K = i;
            break;
        }
    }
    printf("%d ", K);
    memset(f, -1, sizeof(f));
    f[0][0] = 0;
    for(register int i = 1; i <= n; i += 1)
        for(register int j = totw; j >= bot[i].w; j -= 1)
            for(register int k = i; k; k -= 1)
                if(f[k-1][j-bot[i].w] != -1)
                    f[k][j] = max(f[k][j], f[k-1][j-bot[i].w] + bot[i].v);
    int ans = 0;
    for(register int i = totw; i; i -= 1)
    {
        if(f[K][i] >= totw)
        {
            ans = totw - i;
            break;
        }
    }
    printf("%d", ans);
    return 0;
}

Write in the Last

  • Thanks for your attention;
  • Thanks for your toleration of reading my article written by my poor English and my terrable logic.
  • Thanks for the article from https://www.cnblogs.com/wdw828/p/6919446.html which makes me know the English version of 0/1 knapsack problem;
  • This article is written by myself. Reproduction in whole or part without written permission is prohibited.

转载于:https://www.cnblogs.com/LonecharmRiver/articles/9741631.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值