欢迎访问我的新博客:http://www.milkcu.com/blog/

原文地址:http://www.milkcu.com/blog/archives/1395211740.html

引言

这是2013年蓝桥杯全国软件大赛模拟题的第4题,问题是分红酒,方法是BFS。

题目描述

标题:分红酒

有4个红酒瓶子,它们的容量分别是:9升, 7升, 4升, 2升
  开始的状态是 [9,0,0,0],也就是说:第一个瓶子满着,其它的都空着。
  允许把酒从一个瓶子倒入另一个瓶子,但只能把一个瓶子倒满或把一个瓶子倒空,不能有中间状态。这样的一次倒酒动作称为1次操作。
  假设瓶子的容量和初始状态不变,对于给定的目标状态,至少需要多少次操作才能实现?
  本题就是要求你编程实现最小操作次数的计算。
 
  输入:最终状态(逗号分隔)
  输出:最小操作次数(如无法实现,则输出-1)

例如:
输入:
9,0,0,0
应该输出:
0
输入:
6,0,0,3
应该输出:
-1
输入:
7,2,0,0
应该输出:
2

对于编程题目,要求选手给出的解答完全符合ANSI C++标准,不能使用诸如绘图、Win32API、中断调用、硬件操作或与操作系统相关的API。
代码中允许使用STL类库,但不能使用MFC或ATL等非ANSI c++标准的类库。例如,不能使用CString类型(属于MFC类库)。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意选择自己使用的编译环境。

分析

这是一个关于广度优先搜索(BFS)的题目。每个杯中水的量只能为整数,所以状态是有限的,遍历这些状态,并找出距离初始状态最短的路径,即为所求解。

广度优先搜索(BFS)使用队列实现,正如深度优先搜索(DFS)使用堆栈实现。

解题思路确定了,代码实现就简单一点了,当然也会出现小错误。

程序实现

数组模拟队列

队列是一种常用的先进先出(FIFO)的数据结构,常用数组模拟实现。

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef struct Node {int v[4];int dist;
} Node;
int vis[10][10][10];
int count = 0;
int a, b, c, d;
void bfs(void) {Node q[100000];int front = 0;int rear = 1;Node state;int cap[4] = {9, 7, 4, 2};state.v[0] = 9;state.v[1] = state.v[2] = state.v[3] = 0;state.dist = 0;q[front] = state;vis[state.v[1]][state.v[2]][state.v[3]] = 1;while(rear > front) {Node olds = q[front];if(olds.v[0] == a && olds.v[1] == b && olds.v[2] == c && olds.v[3] == d) {cout << olds.dist << endl;return;}for(int i = 0; i < 4; i++) {for(int j = 0; j < 4; j++) {if(i == j) {continue;}// i to jNode & news = q[rear];memcpy(&news, &olds, sizeof(Node));int amount = min(olds.v[i], cap[j] - olds.v[j]);news.v[i] -= amount;news.v[j] += amount;news.dist++;if(!vis[news.v[1]][news.v[2]][news.v[3]]) {vis[news.v[1]][news.v[2]][news.v[3]] = 1;rear++;}}}front++;}cout << "-1" << endl;
}
int main(void) {cin >> a >> b >> c >> d;memset(vis, 0, sizeof(vis));bfs();return 0;
}

STL队列实现

C++ STL标准模板库极大的提高了编程效率,虽然有时不如数组灵活,解答这个问题还是没问题的。

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef struct Node {int v[4];int dist;
} Node;
int vis[10][10][10];
int count = 0;
int a, b, c, d;
void bfs(void) {queue<Node> q;Node state;int cap[4] = {9, 7, 4, 2};state.v[0] = 9;state.v[1] = state.v[2] = state.v[3] = 0;state.dist = 0;q.push(state);vis[state.v[1]][state.v[2]][state.v[3]] = 1;while(!q.empty()) {Node olds = q.front();q.pop();if(olds.v[0] == a && olds.v[1] == b && olds.v[2] == c && olds.v[3] == d) {cout << olds.dist << endl;return;}for(int i = 0; i < 4; i++) {for(int j = 0; j < 4; j++) {if(i == j) {continue;}// i to jNode news;memcpy(&news, &olds, sizeof(Node));int amount = min(olds.v[i], cap[j] - olds.v[j]);news.v[i] -= amount;news.v[j] += amount;news.dist++;if(!vis[news.v[1]][news.v[2]][news.v[3]]) {vis[news.v[1]][news.v[2]][news.v[3]] = 1;q.push(news);}}}}cout << "-1" << endl;
}
int main(void) {cin >> a >> b >> c >> d;memset(vis, 0, sizeof(vis));bfs();return 0;
}

反例分析

解决这个问题的过程也是曲折的,刚开始的时候想使用STL中以整型指针为模板的queue,但是发现队列中每次压入的指针值都是相同的,把这个反例也分享一下吧。

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int vis[10][10][10];
int count = 0;
int a, b, c, d;
void bfs(void) {queue<int *> q;int state[5];int capacity[4] = {9, 7, 4, 2};state[0] = 9;state[1] = state[2] = state[3] = 0;state[4] = 0;q.push(state);vis[state[1]][state[2]][state[3]] = 1;while(!q.empty()) {int * tmp = q.front();q.pop();int oldState[5];memcpy(oldState, tmp, sizeof(oldState));if(oldState[0] == a && oldState[1] == b && oldState[2] == c &&  oldState[3] == d) {cout << oldState[4] << endl;return;}for(int i = 0; i < 4; i++) {for(int j = 0; j < 4; j++) {if(i == j) {continue;}// i to jint newState[5];memcpy(newState, oldState, sizeof(oldState));int quantity = min(oldState[i], capacity[j] - oldState[j]);newState[i] = oldState[i] - quantity;newState[j] = oldState[j] + quantity;cout << newState[0] << ", "<< newState[1] << ", "<< newState[2] << ", "<< newState[3] << ", "<< newState[4] << endl;if(!vis[newState[1]][newState[2]][newState[3]]) {vis[newState[1]][newState[2]][newState[3]] = 1;newState[4]++;cout << newState << endl;q.push(newState);}}}}cout << "-1" << endl;
}
int main(void) {cin >> a >> b >> c >> d;memset(vis, 0, sizeof(vis));bfs();return 0;
}

这个反例,在我的电脑上每次压入队列的值均为0x28fe50,这是由于变量有效期的问题。

小结

虽然文中提供了多种解决方案,但核心思想都是广度优先搜索(BFS)。

当然这个问题也可以扩展一下,把每个步骤的状态打印出来。

(全文完)

转载于:https://www.cnblogs.com/milkcu/p/3808869.html

分红酒 - 蓝桥杯 - 已更新相关推荐

  1. c语言程序设计分巧克力,[蓝桥杯训练] 第八届(2017)省赛 C/C++ A组 T09 - 分巧克力...

    1. 题目 标题: 分巧克力 儿童节那天有K位小朋友到小明家做客.小明拿出了珍藏的巧克力招待小朋友们. 小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形. 为了公平起见,小明需要从这 ...

  2. 2018届蓝桥杯省赛(javaC组)回顾

    绪言 博主去年代表学校参加了省赛,做完了我大概7道题能得分,其他题我不是特别有把握.我心里大概知道能得奖,但是得省一时超乎我自己意外的.往年蓝桥杯省赛一共是10道题.题型有填空题,代码补全题跟,编程题 ...

  3. 2022年蓝桥杯C++B组题解 - 很详细

    本人这次侥幸省1,特做题解复习,哈哈哈- 1.进制转换(5分): 问题描述: 直接计算 2 + 2 * 9 + 2 * 9 * 9 * 9 答案: 1478 2.顺子日期(5分) 这题有争议: 主要在 ...

  4. 蓝桥杯大赛 青少年创意编程 第十三届 C++组

    第十三届 蓝桥杯青少年C++ 中级组11月比赛题目详解 https://www.bilibili.com/video/BV1rR4y1x7mC 第十三届蓝桥杯青少年STEMA比赛(11月)选择题部分的 ...

  5. 包子凑数-蓝桥杯真题 线性方程组求解(c++实现)

    上文链接:日期问题-蓝桥杯真题 具备基础日期知识查看(c++) 包子凑数 小明几乎每天早晨都会在一家包子铺吃早餐.他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子.每种蒸笼都有非常多笼,可 ...

  6. 历届蓝桥杯青少年Scratch编程选拔赛 STEMA评测比赛真题解析【持续更新 已更新至49题】

    历届蓝桥杯scratch选拔赛真题 第十届.十一届.十二届.十三届蓝桥杯选拔赛STEMA比赛真题解析 选拔赛真题49-购物程序 [蓝桥杯选拔赛真题48]Scratch购物程序 少儿编程scratch蓝 ...

  7. 历届蓝桥杯Scratch编程国赛 初级 中级 青少年编程比赛国赛真题解析【持续更新 已更新至27题】

    历届蓝桥杯国赛真题 第十三界.十二届.十一届等历届青少年蓝桥杯Scratch编程比赛国赛真题解析 国赛真题01-河马带球[试看] [蓝桥杯国赛真题01]Scratch河马带球 少儿编程蓝桥杯Scrat ...

  8. 历届蓝桥杯Scratch编程省赛 初级 中级 青少年编程比赛省赛真题解析【持续更新 已更新至35题】

    历届蓝桥杯scratch省赛真题 历年蓝桥杯Scratch编程比赛省赛真题详细解析 省赛真题35-水面倒影 [蓝桥杯省赛真题35]Scratch水面倒影 少儿编程scratch编程蓝桥杯省赛真题讲解_ ...

  9. 蓝桥杯软件大赛---分红酒(广度优先搜索)

    题目: 标题:分红酒   有4个红酒瓶子,它们的容量分别是:9升, 7升, 4升, 2升   开始的状态是 [9,0,0,0],也就是说:第一个瓶子满着,其它的都空着.   允许把酒从一个瓶子倒入另一 ...

  10. 历届蓝桥杯青少年编程选拔赛 科技素养题真题讲解 STEMA评测比赛真题解析【持续更新 已更新至18套】

    信息素养(科技素养)的重要性 教育部等多个部门多次发文强调中小学生信息素养的重要性,而且已经纳入到新课标里面:要提升学生信息素养.各地要指导和推动中小学按照国家课程方案和课程标准开齐开足开好信息技术课 ...

最新文章

  1. 详解 | SLAM回环检测问题
  2. Sublime Text 无法使用Package Control或插件安装失败的解决方法
  3. 这 17 个 JVM 参数,高级 Java 必须掌握!
  4. ERROR in multi ./src/main.js dist/bundle.js
  5. java this用法_java中this用法小结
  6. @ModelAttribute使用详解
  7. 2012-01-17-03
  8. 利用html5实现上传图片预览
  9. Ubuntu 12.04 下安装 Eclipse
  10. 985硕士程序员年薪80万!邻居眼中不如一个老师?你怎么看?
  11. AAAI-19录用论文
  12. ECMAScript和JavaScript的区别
  13. Excel VBA小程序03-快速提取单元格中的数字和非数字
  14. CSS font-family 中英文名称集合
  15. 任正非最新签发:鼓励来华为“胡说八道”
  16. 99物联金手指模组AFW127PI
  17. rsync:基本命令和用法
  18. 选择java还是python-还在纠结选Python还是Java?看完就有数了
  19. 天翼云从业认证(4.4)异构双活云灾备实例
  20. golang调用网易云API

热门文章

  1. 大腾讯的第一个开源项目「Tinker」
  2. python基础之迭代器、生成器、装饰器
  3. 完全重构一个项目的前端代码
  4. 后缀数组模板 (详细注释)
  5. Spring学习总结(2)——Spring IOC的前世今生
  6. 一致性算法中的节点下限(转)
  7. 超市负库存产生的原因及对策
  8. Postgresql----libpq
  9. 最新的.net书籍教程 更新时间:2005-9-5
  10. emule学习与分析二 上 建立连接过程分析