洛谷题目:P1215 [USACO1.4] 母亲的牛奶 Mother‘s Milk 题解(本题简)

介绍:

前言:

这是一道经典的水桶分水问题,也就是 BFS广度优先搜索的模版题。这道题呢不是求某一次的 c 值,而是找出所有操作后能达到的、a 为空的局面,把每一种局面下对应的 c 桶存量收集起来,去重并升序输出。

#解题思路步骤:

1、明确问题核心:

1.1、题目中给定了 a ,b , c 三个容量的牛奶痛;每次只能见一个桶倒入另一个桶,知道源桶倒空或者装满了,牛奶的重量是不变的。要求我们找出在 a 桶为空的时候,c 桶所剩下的数值那就升序输出就可以啦。

1.2、既然在前言说明了考察的知识点,那我们直接不绕弯子了。首先,这道题在小亦的认知里适用于 BFS 的做法,就是去重遍历全部的一个状态,如果说你用其他的话比如暴力枚举,所有倒水的组合是不记录已访问的状态的,而且还会重复循环和搜索,所以呢适用于 BFS 的做法啦。

2、状态和倒水逻辑:

我们其实无法直接列举所有 c 的可能性,你得想要定义三组代表一种状态来模拟6种两年相互倒水的一个状态,然后呢在逐步判断是否都满足 a 为空的条件。

3、状态和存储:

3.1、首先 visa bc 布尔标记数组,分别记录该三元组的状态时候是否已经遍历过了。

3.2、ans集合,自动去重和升序存储所有a桶为空时c的数值。

4、BFS遍历:

整体呢使用队列来实现 BFS,小亦列举了三步:分别是初始化、状态扩展、收集结果。

4.1、初始化,从 (0,0,C)入队,标记 vis00C= ture,此时a空,直接将c=C存进答案集合。

4.2、队列循环扩渣,取出队首的桶状态,执行6种倒水操作,随后计算倒水的新桶容量,若没有访问,那就标记访问+入队🉑。

4.3、收集和输出,每取出一个状态的时候,如果当前 a 桶的存量为0,那就把当前c的数值存入集合里去,遍历有序集合,按着空哥分隔输出所有c的可能值。到此结束~

##复杂度:

1、时间复杂度:

2、时间复杂度:

###代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct State {
    int a, b, c;
};
bool vis[21][21][21] = {false};
set<int> ans;
int A, B, C;
void pour(int &x_val, int &y_val, int mx, int my) {
    int can = min(x_val, my - y_val);
    x_val -= can;
    y_val += can;
}
void bfs() {
    queue<State> q;
    q.push({0, 0, C});
    vis[0][0][C] = true;

    while (!q.empty()) {
        State cur = q.front();
        q.pop();
        if (cur.a == 0) {
            ans.insert(cur.c);
        }

        int a = cur.a, b = cur.b, c = cur.c;
        int na = a, nb = b, nc = c;
        pour(na, nb, A, B);
        if (!vis[na][nb][nc]) {
            vis[na][nb][nc] = true;
            q.push({na, nb, nc});
        }
        na = a, nb = b, nc = c;
        pour(na, nc, A, C);
        if (!vis[na][nb][nc]) {
            vis[na][nb][nc] = true;
            q.push({na, nb, nc});
        }
        // 3. b->a
        na = a, nb = b, nc = c;
        pour(nb, na, B, A);
        if (!vis[na][nb][nc]) {
            vis[na][nb][nc] = true;
            q.push({na, nb, nc});
        }
        // 4. b->c
        na = a, nb = b, nc = c;
        pour(nb, nc, B, C);
        if (!vis[na][nb][nc]) {
            vis[na][nb][nc] = true;
            q.push({na, nb, nc});
        }
        // 5. c->a
        na = a, nb = b, nc = c;
        pour(nc, na, C, A);
        if (!vis[na][nb][nc]) {
            vis[na][nb][nc] = true;
            q.push({na, nb, nc});
        }
        // 6. c->b
        na = a, nb = b, nc = c;
        pour(nc, nb, C, B);
        if (!vis[na][nb][nc]) {
            vis[na][nb][nc] = true;
            q.push({na, nb, nc});
        }
    }
}

int main() {
    cin >> A >> B >> C;
    bfs();
    for (auto it = ans.begin(); it != ans.end(); ++it) {
        if (it != ans.begin()) cout << " ";
        cout << *it;
    }
    cout << endl;
    return 0;
}

--- 感谢观看---

制作:Code.小亦
代码提供:Code.小亦
题目思路部分提供:无

代码部分思路提供:无

知识共享:无

知识查找来源:无

初审:Code.小亦。

终审:Code.小亦。

本文章属于原创作品,禁止任何人进行转载,除合作之外!!

如在阅读中发现知识性错误、代码错误、错别字错误等情况私信博主或评论或通过邮箱2952104443@qq.com。

另:题目来源:首页 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

特:本文章/专栏在知乎网站合规授权发布。

相关推荐
CHHH_HHH1 小时前
【C++11】深入解析C++可变参数模板
开发语言·c++·算法·stl·c++11
KJ_BioMed2 小时前
从PDB到高亲和力分子:De novo生成式计算化学Pipeline剖析
算法·生物医药·生物科研·科研干货·化合物设计
一个王同学3 小时前
从零到一 | CV转多模态大模型 | week17 | LLM 推理优化 & vLLM 详解
人工智能·深度学习·算法·机器学习·计算机视觉·vllm
旖-旎4 小时前
《LeetCode 53 最大子数组和 || LeetCode 918 环形子数组的最大和》
c++·算法·leetcode·动态规划
变量未定义~4 小时前
单调栈+倍增思想 皇家守卫【算法赛】、单调队列 附近最小
算法
QN1幻化引擎4 小时前
给 AI 做一次「意识体检」——基于 QN1 幻化引擎的灵鉴意识识别框架与 DalinX V5 实测
大数据·数据结构·人工智能·算法·架构
拂拉氏4 小时前
【知识讲解】 AVL树从基本成员的介绍到核心接口的实现(插入、判断、删除等等)
数据结构·算法·avl树
可靠的仙人掌5 小时前
SAC(Soft Actor-Critic)算法底座
开发语言·算法·php
c238565 小时前
《动态规划:从“傻傻穷举”到“过目不忘”的修仙之路》
c++·算法·动态规划