倒水问题(bfs)

2023-05-16

题意概述

"fill A"表示倒满A杯,"empty A"表示倒空A杯,"pour A B" 表示把A的水倒到B杯并且把B杯倒满或A倒空。

Input

输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。

Output

你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。

思路

全部操作共有六种,分别是fill A,fill B,empty A,empty B,pour A B,pour B A
整体思路是:
1.用一个结构体记录杯子a、b的状态并重载比较操作。

struct Status 
{
	int a,b;
	bool operator<(const Status &s) const 
	{
		return a!=s.a ? a<s.a : b<s.b;
	}
};

2.用map记录杯子a和b当前和上一步的状态,利用队列实现bfs。
3.在bfs函数内部,每次取队首元素,首先判断是否得到容量为C的水(特判终点)。然后分四大类情况讨论:倒空a杯b杯不变,倒空b杯a杯不变,续满a杯,续满b杯。后两种情况又需考虑a杯和b杯当前水量的总和与要续满的杯的容量的关系,分为倒满一杯或倒空另一杯。
4.每种情况下,都需要更新记录状态的map。
5.最后用递归输出解决方案,输出前,需要增加一个输出判断的函数print_judge( ),因为在bfs中我们只是记录了每一步的状态,还需要根据前后状态的变化输出对应的操作。

void print_judge(Status &s,Status &t)
{//通过判断倒水操作的前后状态来判断进行了什么操作 
	if(s.a==t.a)
	{//a杯没变 
		if(t.b==B) //操作之后b杯是满的 
			cout<<"fill B"<<endl;
		else
			cout<<"empty B"<<endl;
	}
	else if(s.b==t.b)
	{//b杯没变 
		if(t.a==A) 
			cout<<"fill A"<<endl;
		else
			cout<<"empty A"<<endl; 
	}
	else{
		if(t.a<s.a) //a杯少了 
			cout<<"pour A B"<<endl;
		else
			cout<<"pour B A"<<endl; 
	}
}

代码

#include <iostream>
#include<queue>
#include<map>
using namespace std;

struct Status 
{
	int a,b;
	bool operator<(const Status &s) const 
	{
		return a!=s.a ? a<s.a : b<s.b;
	}
};
queue<Status> Q;
map<Status, Status> from;//map用来记录a/b杯水的上一状态和当前状态 
int A,B,C;
//string s[]={"fill A","fill B","empty A","empty B","pour A B","pour B A"}; 

void print_judge(Status &s,Status &t)
{//通过判断倒水操作的前后状态来判断进行了什么操作 
	if(s.a==t.a)
	{//a杯没变 
		if(t.b==B) //操作之后b杯是满的 
			cout<<"fill B"<<endl;
		else
			cout<<"empty B"<<endl;
	}
	else if(s.b==t.b)
	{//b杯没变 
		if(t.a==A) 
			cout<<"fill A"<<endl;
		else
			cout<<"empty A"<<endl; 
	}
	else{
		if(t.a<s.a) //a杯少了 
			cout<<"pour A B"<<endl;
		else
			cout<<"pour B A"<<endl; 
	}
}
//递归输出每步操作
void print(Status &p) 
{
    if ( from.find(p) == from.end() || (p.a == 0&&p.b==0) )
    {
        return;
    }
    print(from[p]); // 递归
    print_judge(from[p],p);
    
}

void refresh(Status &s, Status &t) 
{
    if ( from.find(t) == from.end() ) 
    { // 特判合法,加入队列
        from[t] = s;
        Q.push(t);
    }
}

void bfs() 
{
	// 起点, 两杯水都空
	Status s,t; s.a=0; s.b=0; 
	Q.push(s);

    while (!Q.empty()) 
    {
    	// 取队首
        s = Q.front(); Q.pop();
        // 特判到达终点
        if (s.a == C || s.b == C) {
            print(s); // 输出方案
            return;
        }

        // 倒空 a 杯的水
        if (s.a > 0) {
            t.a = 0;  // 倒空
            t.b = s.b;// b 杯不变
            refresh(s, t);
        }

        // 同理,倒空 b 杯的水
        if (s.b > 0) {
            t.b = 0;  // 倒空
            t.a = s.a;// a 杯不变
            refresh(s, t);
        }

        // a 杯未满,续满 a 杯
        if (s.a < A) 
        {
        	// 续满 a 杯
        	t.a = A;  
        	t.b = s.b;
            refresh(s, t);
            // 考虑倒入
            if (s.b != 0) 
            {
                if (s.a + s.b <= A) 
                {
                    t.a = s.a + s.b;
                    t.b = 0;
           			refresh(s, t);
                } else 
                {
                    t.a = A;
                    t.b = s.a + s.b - A;
            		refresh(s, t);
                }
            }
        }

        // 同理,b 杯未满,续满 b 杯
        if (s.b < B) 
        {
            t.a = s.a;
            t.b = B;
            refresh(s, t);
            if (s.a != 0) 
            {
                if (s.a + s.b <= B) 
                {
                    t.a = 0;
                    t.b = s.a + s.b;
                    refresh(s, t);
                } else 
                {
                    t.a = s.a + s.b - B;
                    t.b = B;
                    refresh(s, t);
                }
            }
        }
    }
}
int main() 
{ 
    while(cin>>A>>B>>C)
    {
    	while(!Q.empty()){
    		Q.pop();
		}
		from.clear();
    	bfs();
    	cout<<"success"<<endl;
	}
    return 0;
}

总结

1.在main函数里每次调用bfs函数前要记得先把队列和map清空!!否则后面的输出会出错。
2.关于如何输出语句纠结了好久,最后决定根据操作前后两个杯子的状态确定输出的操作,只需要在递归输出的每一步调用判断函数输出就好啦。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

倒水问题(bfs) 的相关文章

随机推荐

  • win10 Remote Host 调试 ubuntu18.04 中有libXXX.so库,报/usr/lib/ld 找不到-lxxx

    按照下图操作 xff0c 找到自己的交叉编译环境中的g 43 43 和gcc工具可以解决
  • CDN和Akamai

    最近在看分布式相关的东西 xff0c 在看到HTTP Caching的时候 xff0c 提到CDN和Akamai 以前对这些东西都是一无所知啊 记录一下吧 http zh wikipedia org wiki E5 85 A7 E5 AE
  • 在Centos7环境安装GitLab

    https about gitlab com install centos 7 1 Install and configure the necessary dependencies On CentOS 7 and RedHat Oracle
  • 免费的天气api

    这是最近网上查询到关于天气的api xff0c 大部分的接口都是收费 xff0c 有部分接口虽然免费 xff0c 但查询到的信息量特别不全 但好在有几个免费接口倒是不错 xff0c 倒是可以使用 免费的天气api 高德地图 天气查询免费ap
  • Enlightenment官网介绍

    Enlightenment和EFL的官方网站 xff1a http www enlightenment org Enlightenment xff1a Enlightenment 是一个旗舰项目 它曾经是一个不起眼的 X11 窗口管理器 W
  • Enlightenment 是窗口管理器,Enlightenment 是桌面外壳,Enlightenment是创建漂亮应用程序的材料

    Enlightenment 是窗口管理器 xff0c Enlightenment 是桌面外壳 xff0c Enlightenment是创建漂亮应用程序的材料 xff0c Enlightenment xff0c 或者简单的一个 e xff0c
  • ubuntu安装nvidia显卡驱动报错:”The CC version check failed”

    参考过不少博主回答的问题 xff0c 但都存在很多问题 xff0c 或者比较麻烦 xff0c 给大家推荐一下我自己尝试解决后比较好的一个方案 xff1a 出现这个问题的原因是因为驱动可能比较新 xff0c 系统内核的gcc版本和编译器的默认
  • codeforces1169C 二分答案+思维

    1169C 1700的题 xff0c 然而比赛的时候没有做出来 题意 xff1a 给你一个n表示序列长度为n xff0c 还有一个m表示这个序列的最大值小于m 然后对这个数组进行多次操作 xff0c 一次操作为 对ai xff0c aj x
  • python用pip装第三方库numpy时报错:UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 7: ordi

    python用pip装第三方库numpy时一直报错 xff1a UnicodeDecodeError 39 ascii 39 codec can 39 t decode byte 0xc3 in position 7 ordinal not
  • debian8 jessie 更换为国内源

    编辑 etc apt sources list文件 xff1a 用 注释掉老的源 添加新的源 xff0c deb http mirrors 163 com debian jessie main non free contrib deb ht
  • 09、Flutter FFI Dart Native API

    Flutter FFI 学习笔记系列 Flutter FFI 最简示例 Flutter FFI 基础数据类型 Flutter FFI 函数 Flutter FFI 字符串 Flutter FFI 结构体 Flutter FFI 类 Flut
  • Copilot 自动编程AI工具

    OpenAI与GitHub联合构建的AI自动编程工具Copilot xff0c Copilot基于自然语言处理模型GPT 3搭建而成 xff0c Copilot预览版已经正式上线Visual Studio Code平台 OpenAI的GPT
  • SQLite的SQL语法

    SQLite库可以解析大部分标准SQL语言 但它也省去了一些特性 并且加入了一些自己的新特性 这篇文档就是试图描述那些SQLite支持 不支持的SQL语法的 查看关键字列表 如下语法表格中 xff0c 纯文本用蓝色粗体显示 非终极符号为斜体
  • 动态链接库dll(Windows/C++)

    1 概念 xff08 1 xff09 动态链接库广泛用于Windows系统及应用程序 xff0c 不能单独被执行 xff0c 在应用程序运行期间被动态调用的模块文件 区别于静态链接库 xff0c 均属于独立的代码编译模块 xff0c 但静态
  • 【Java】反射时获取父类属性并赋值

    1 反射获取父类 在反射获取类里的所有属性的时候 xff0c 会遇到无法访问父类extends里面的值 这时候需要访问父类需要调用Class的方法getSuperclass 对父类进行遍历field 同时如果不想遍历到Object或者某个类
  • linux软件包安装命令——apt-get

    apt get是linux中APT软件包的管理工具 采用shell命令行的方式完成软件的安装 更新 卸载等操作 1 语法 apt get xff08 选项 xff09 xff08 参数 xff09 选项 xff1a c 指定配置文件 o 直
  • 浅谈路由器的wan、lan、wlan口和vlan/trunk口

    背景 另一篇博文分析了一个实际的路由问题 xff0c 为方便问题分析 xff0c 在此列出常用概念 vlan中的trunk口 VLAN Trunk以及三层交换 可以把switch某一端口设为trunk 端口 问题 IP地址分类 xff1a
  • bzoj4864 [BeiJing 2017 Wc]神秘物质

    http www elijahqi win 2018 01 26 bzoj4864 beijing 2017 wc E7 A5 9E E7 A7 98 E7 89 A9 E8 B4 A8 20 E2 80 8E Description 21
  • mysql8设置远程连接详细教程

    这是转载StackOverFlow上的回答 xff0c 原回答点此这里 Remote Access in MySQL 8 Allow access from any host sudo nano etc mysql mysql conf d
  • 倒水问题(bfs)

    题意概述 34 fill A 34 表示倒满A杯 xff0c 34 empty A 34 表示倒空A杯 xff0c 34 pour A B 34 表示把A的水倒到B杯并且把B杯倒满或A倒空 Input 输入包含多组数据 每组数据输入 A B