题解倒水

Posted kcn999

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解倒水相关的知识,希望对你有一定的参考价值。

题目描述

  一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子)
显然在某些情况下CC无法达到目标,比如N=3, K=1,因为你会发现,把任意一个瓶子倒到另一瓶子后,只剩下一个1升水的瓶子和一个2升水的瓶子,这两个瓶子无法再相互倒水了,因此超过了K。 此时CC可以重新买一些新的瓶子(新瓶子容量无限,开始时有1升水),以到达目标,例如再买一个新瓶子,那么就有2个1升水的瓶子,把它们倒在一起,就得到一个2升水的瓶子,这样再和之前的2升水的瓶子倒在一起,最后就只剩下一个4升水的瓶子了,满足条件。
  现在CC想知道,最少需要买多少新瓶子才能达到目标呢?如果无论买多少个瓶子都无法满足条件,则输出-1。

 

驶入输出格式

输入格式

  多组测试数据。
    第一行:一个整数r,表示共有r组测试数据,1<=r<=10。
    每组测试数据的格式是:
     一行两个正整数, N, K (1<=N<=10^7,K <= 1000)。

 

输出格式

  共r行,每行对应一组测试数据,一个非负整数,表示最少需要买多少新瓶子。

 

输入输出样例

输入样例

3
3  1
13  2
1000000  5

 

输出样例

1
3
15808

 

题解

  可以看出此题不存在-1的情况。

  其实可以用$n$的二进制形式来表示起始的瓶子拥有情况,DFS一遍所有添加情况即可。

技术图片
#include <iostream>

#define lowbit(x) ((x) & -(x))

using namespace std;

int G;
int n, k;
int maxn; 
int ans;

void DFS(int now, int lim, int cnt)
{
    if(now > maxn) return;
    int tmp = now, tot = 0;
    while(tmp)
    {
        ++tot;
        tmp -= lowbit(tmp);
    }
    if(tot <= k) 
    {
        ans = min(cnt, ans);
        return;
    }
    tmp = now;
    while(tmp)
    {
        if(lowbit(tmp) > lim) DFS(now + lowbit(tmp), lowbit(tmp), cnt + lowbit(tmp));
        tmp -= lowbit(tmp);
    }
    return;
} 

int main()
{
    cin >> G;
    int tmp;
    while(G--)
    {
        cin >> n >> k;
        tmp = n;
        while(tmp != lowbit(tmp)) 
        {
            tmp -= lowbit(tmp);
        }
        maxn = tmp << 1;
        ans = 1 << 30;
        DFS(n, 0, 0);
        cout << ans << "
"; 
    }
    return 0;
}
参考程序

 

以上是关于题解倒水的主要内容,如果未能解决你的问题,请参考以下文章

题解Luogu P1582 倒水 二进制

1226 倒水问题

USACO Mother&#39;s Milk(bfs)

POJ 3585 Accumulation Degree 题解

Problem E: 倒水(Water)

UVA10603Fill题解--BFS