【DFS】巧妙取量的倒油问题

本文探讨了一个经典的油桶倒油问题,通过深度优先搜索算法寻找从三个不同容量的油桶中精确倒出特定数量油的最佳步骤。文章详细解释了如何通过递归算法遍历所有可能的倒油顺序,以找到达到目标油量所需的最少倒油次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

【题目描述】 
  有三个容器,容量分别为 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

思路:使用深度优先搜索来搜索所有可能的倒油顺序

#include<vector>
#include<cstdio>

using namespace std;

struct oil_box //油桶
{
	int oil_left; //桶内剩余油量
	int volume_left; //桶内剩余空间
};

int target_oil;//目标油量
int step_min = 50;//当前最小步数,初始设为50步
int oil_total; //总油量

void DFS(vector<oil_box> vc, int index_a, int index_b, int step)//向量vc存储所有油桶的信息,index_a是上一次出油的油桶索引,index_b是上一次接油的油桶索引,step为当前步数
{
	if (step >=step_min || (vc[0].oil_left==oil_total&&step!=1))//剪枝
	{
		return;
	}
	
	int len = vc.size();
	for (int i = 0; i < len; i++)
	{
		int index_now = i;
		oil_box box_now = vc[index_now];
		if (box_now.oil_left != 0)
		{
			for (int j = 1; j < len; j++)
			{
				int index_next = (index_now + j) % len;
				oil_box box_next = vc[index_next];
				if (index_now != index_b || index_next != index_a)//避免进入死循环
				{
					if (box_now.oil_left > box_next.volume_left)
					{
						box_now.oil_left = box_now.oil_left - box_next.volume_left;
						box_now.volume_left = box_now.volume_left + box_next.volume_left;
						box_next.oil_left = box_next.oil_left + box_next.volume_left;
						box_next.volume_left = 0;
					}
					else
					{
						box_next.oil_left = box_next.oil_left + box_now.oil_left;
						box_next.volume_left = box_next.volume_left - box_now.oil_left;
						box_now.volume_left = box_now.volume_left + box_now.oil_left;
						box_now.oil_left = 0;
					}
					if (box_now.oil_left == target_oil || box_next.oil_left == target_oil)
					{
						if (step < step_min)
						{
							step_min = step;
						}
						return;
					}
					vector<oil_box> vc_new = vc;
					vc_new[index_now] = box_now;
					vc_new[index_next] = box_next;
					DFS(vc_new, index_now,index_next, step + 1);
				}
			}
		}
	}
}

int main()
{
	oil_box a, b, c;
	scanf("%d%d%d%d", &a.oil_left, &b.volume_left, &c.volume_left, &target_oil);
	oil_total = a.oil_left;
	a.volume_left = 0;
	b.oil_left = 0;
	c.oil_left = 0;


	vector<oil_box> vc;
	vc.push_back(a);
	vc.push_back(b);
	vc.push_back(c);

	DFS(vc, 0, 0, 1);
	if (step_min != 50)
	{
		printf("%s\n", "yes");
		printf("%d", step_min);
	}
	else
	{
		printf("%s", "no");
	}
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值