扩展欧几里德算法解决问题A:Jugs

codeup的Jugs题目需要使用扩展欧几里德算法解决:

题目链接:http://codeup.hustoj.com/problem.php?cid=100000609&pid=0
这道题出的有点奇怪,学习下扩展欧几里德算法就行了,不要在这题浪费太多时间
题目的一小段提示:
倒水问题的经典形式是这样的:

“假设有一个池塘,里面有无穷多的水。现有2个空水壶,容积分别为5升和6升。问题是如何只用这2个水壶从池塘里取得3升的水。”

当然题外是有一些合理的限制的,比如从池塘里灌水的时候,不管壶里是不是已经有水了,壶一定要灌满,不能和另一个壶里的水位比照一下“毛估估”(我们可以假设壶是不透明的,而且形状也不同);同样的,如果要把水从壶里倒进池塘里,一定要都倒光;如果要把水从一个壶里倒进另一个壶里,也要都倒光,除非在倒的过程中另一个壶已经满了;倒水的时候水没有损失(蒸发溢出什么的)等等等等。

事实上,要解决上面这题,你只要用两个壶中的其中一个从池塘里灌水,不断地倒到另一个壶里,当第二个壶满了的时候,把其中的水倒回池塘里,反复几次,就得到答案了。以5升壶(A)灌6升壶(B)为例:

A  B
0  0
5  0  A→B
0  5
5  5  A→B
4  6
4  0  A→B
0  4
5  4  A→B
3  6

给出100分的AC代码链接:https://blog.csdn.net/xlrll/article/details/105505502

Zoj的jugs题目需要使用BFS算法解决:

题目链接:https://zoj.pintia.cn/problem-sets/91827364500/problems/91827364504
AC代码

#include <stdio.h>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;

struct Jug {
	int Ca, Cb;
	vector<int> ops;
} tempJug;

int Ca, Cb, N;
string opStr[] = {"fill A", "fill B", "empty A", "empty B", "pour A B", "pour B A"};

bool check(Jug jug, int opNum) {
    //其他的校验在switch里面,这里对一些特殊的情况处理
    //最后一个操作是fill A,接下来就不要empty A
    if(jug.ops[jug.ops.size()-1] == 0 && opNum == 2) {
        return false;
    }
    //最后一个操作是fill B,接下来就不要empty B
    if(jug.ops[jug.ops.size()-1] == 1 && opNum == 3) {
        return false;
    }
    //最后一个操作是pour A B,接下来就不要pour B A
    if(jug.ops[jug.ops.size()-1] == 4 && opNum == 5) {
        return false;
    }
    //最后一个操作是pour B A,接下来就不要pour A B
    if(jug.ops[jug.ops.size()-1] == 5 && opNum == 4) {
        return false;
    }

    return true;
}

void BFS() {
	queue<Jug> q;
	Jug jug1, jug2;
	//放入fill A操作
	jug1.Ca = Ca;
	jug1.Cb = 0;
	jug1.ops.push_back(0);
	q.push(jug1);
	//放入fill B操作
	jug2.Ca = 0;
	jug2.Cb = Cb;
	jug2.ops.push_back(1);
	q.push(jug2);
	while(!q.empty()) {
		Jug top = q.front();
		q.pop();
		if(top.Cb == N) {
			//打印操作
			for(int i = 0; i < top.ops.size(); i++) {
				cout<<opStr[top.ops[i]]<<endl;
			}
			printf("success\n");
			return;
		}
		for(int i = 0; i < 6; i++) {
            //防止内存超限或者运行超时!
            if(check(top, i) == false) continue;
			switch(i) {
				case 0:
					if(top.Ca < Ca) {
						tempJug.Ca = Ca;
						tempJug.Cb = top.Cb;
						//注意先把top的ops赋值给tempJug的ops
						tempJug.ops = top.ops;
						tempJug.ops.push_back(0);
						q.push(tempJug);
					}
					break;
				case 1:
					if(top.Cb < Cb) {
						tempJug.Ca = top.Ca;
						tempJug.Cb = Cb;
						tempJug.ops = top.ops;
						tempJug.ops.push_back(1);
						q.push(tempJug);
					}
					break;
				case 2:
					if(top.Ca > 0) {
						tempJug.Ca = 0;
						tempJug.Cb = top.Cb;
						tempJug.ops = top.ops;
						tempJug.ops.push_back(2);
						q.push(tempJug);
					}
					break;
				case 3:
					if(top.Cb > 0) {
						tempJug.Ca = top.Ca;
						tempJug.Cb = 0;
						tempJug.ops = top.ops;
						tempJug.ops.push_back(3);
						q.push(tempJug);
					}
					break;
				case 4:
					if(top.Cb < Cb && top.Ca > 0) {
						int need = Cb - top.Cb;
						if(top.Ca >= need) {
							tempJug.Cb = Cb;
							tempJug.Ca = top.Ca - need;
						} else {
							tempJug.Cb = top.Cb + top.Ca;
							tempJug.Ca = 0;
						}
						tempJug.ops = top.ops;
						tempJug.ops.push_back(4);
						q.push(tempJug);
					}
					break;
				case 5:
					if(top.Ca < Ca && top.Cb > 0) {
						int need = Ca - top.Ca;
						if(top.Cb >= need) {
							tempJug.Ca = Ca;
							tempJug.Cb = top.Cb - need;
						} else {
							tempJug.Ca = top.Ca + top.Cb;
							tempJug.Cb = 0;
						}
						tempJug.ops = top.ops;
						tempJug.ops.push_back(5);
						q.push(tempJug);
					}
					break;
			}
		}
	}
}

int main() {

	while(~scanf("%d %d %d", &Ca, &Cb, &N)) {
		BFS();
	}

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值