算法笔记练习 8.2 广度优先搜索(BFS) 问题 E: 【宽搜入门】巧妙取量

算法笔记练习 题解合集

本题链接

题目

题目描述
【题目描述】
  有三个容器,容量分别为 a,b,c(a> b > c ),一开始a装满油,现在问是否只靠abc三个容器量出k升油。如果能就输出“yes”,并且说明最少倒几次,否则输出“no”。例如:10升油在10升的容器中,另有两个7升和3升的空容器,要求用这三个容器倒油,使得最后在abc三个容器中有一个刚好存有5升油,问最少的倒油次数是多少?(每次倒油,A容器倒到B容器,或者A内的油倒完,或者B容器倒满。
 10 7 3
(10 0 0)
(3 7 0):第一次
(3 4 3):第二次
(6 4 0):第三次
(6 1 3):第四次
(9 1 0):第五次
(9 0 1):第六次
(2 7 1):第七次
(2 5 3):第八次,出现5了。

Input
【输入格式】
  有多组测试数据。
  输入a,b,c, k四个正整数( 100 ≥ a > b > c≥1 , 1≤k< 100 )

Output
【输出格式】
  如果能得到k就输出两行。
  第一行“yes”,第二行为最少的次数
  否则输出“no”

Sample Input

10 7 3 5

Sample Output

yes
8

思路

大思路参考 问题 C: 【宽搜入门】8数码难题 和 问题 D: 【宽搜入门】魔板。(感觉作者总喜欢把难题放在前面…)

这个题我动脑子的地方在于用两层for循环和一个倒水函数实现了对下一个合法情况的试探。

代码

#include 
#include 
#include 
#include 
using namespace std;

int goal;
bool outputed;
vector<int> V(3), temp(3);
map<vector<int>, int> moveCnt;

inline vector<int> pour(vector<int> now, int src, int des) {
	if (now[src] > 0 && now[des] < V[des]) {
		int temp = min(now[src], V[des] - now[des]);
		now[src] -= temp;
		now[des] += temp;
	}
	return now;
} 
void BFS() {
	outputed = false;
	moveCnt.clear();
	moveCnt[ {V[0], 0, 0} ] = 0;
	queue<vector<int> > Q;
	Q.push( {V[0], 0, 0} );
	while (!Q.empty()) {
		vector<int> top = Q.front();
		for (int i = 0; i < 3; ++i) {
			if (top[i] == goal) {
				printf("yes\n%d\n", moveCnt[top]); 
				outputed = true;
				return;
			} 
		} 
		Q.pop();
		for (int i = 0; i < 3; ++i) {
			for (int j = 0; j < 3; ++j) {
				if (i == j)
					continue;
				temp = pour(top, i, j);
				if (!moveCnt.count(temp)) {
					moveCnt[temp] = moveCnt[top] + 1;
					Q.push(temp);
				} 
			} 
		} 
	} 
} 

int main() {
	while (scanf("%d%d%d%d", &V[0], &V[1], &V[2], &goal) != EOF) { 
		BFS();
		if (!outputed)
			puts("no"); 
	}
	return 0;
} 

你可能感兴趣的:(算法笔记)