分油

原文链接: 分油

上一篇: hdu2612 Find a way

下一篇: HDU 2602 Bone Collector

xmy开车

发布时间: 2017年6月26日 10:45   最后更新: 2017年6月29日 10:20   时间限制: 1000ms   内存限制: 128M

描述

某天xmy与他的朋友开车去兜风,为了炫富,他们2个人开了2辆车,然而不幸得是,他们的车同时没有了油,但此时每辆车想要到加油站还需要S/2升的油量,现在有一个好心人路过,给了他们3个容器:一个为S升(里面包含S升的汽油),一个为N升,一个为M升(这两个都是空的,且3个容器都没有刻度)。其中S=N+M,现在问你,能否通过它们3个之间相互倒的方式,来使得汽油均分(这样xmy和他的朋友就可以一起到加油站啦!)。

如果能的话,输出最少需要倒的次数,不能的话输出"NO"。这对于xmy来说太Naive啦,但是他想考考你~

输入

三个整数 : S , N 和 M是两个杯子的容量(全部不超过100),以"0 0 0"结束。

输出

如果能平分的话请输出最少要倒的次数,否则输出"NO"。

样例输入1 复制

7 4 3 4 1 3 0 0 0

样例输出1

NO
3

#include <iostream>
#include <cstdio>
#include <queue>
#include <set>

using namespace std;
int S, N, M;
struct Node {
	int s, n, m, step;
	Node() {}
	Node(int s, int n, int m, int step) :s(s), n(n), m(m), step(step) {}
	friend int operator <(const Node& a, const Node& b) {
		if (a.s != b.s)	return a.s < b.s;
		if (a.n != b.n)	return a.n < b.n;
		if (a.m != b.m)	return a.m < b.m;
		return 0;
	}
};


int main(int argc, char *argv[]) {
	while (scanf("%d%d%d", &S, &N, &M) == 3 && (S || N || M)) {
		Node start(S, 0, 0, 0);
		queue<Node> q;
		set<Node> vis;
		q.push(start);
		vis.insert(start);

		bool flag = 0;

		if (S % 2 == 1 || (N >= S && M >= S)) {
			printf("NO\n");
			continue;
		}

		while (!q.empty()) {
			Node t = q.front();
			q.pop();

			if ((t.s == S / 2 && t.n == S / 2) ||
				(t.s == S / 2 && t.m == S / 2) ||
				(t.n == S / 2 && t.m == S / 2)) {
				flag = 1;
				printf("%d\n", t.step);
				break;
			}
			Node next;
			//s-->n
			if (t.s > 0 && t.n < N) {
				if (t.s >= N - t.n) {
					next.s = t.s - (N - t.n);
					next.n = N;
					next.m = t.m;
					next.step = t.step + 1;
				} else {
					next.s = 0;
					next.n = t.s + t.n;
					next.m = t.m;
					next.step = t.step + 1;
				}
				if (vis.find(next) == vis.end()) {
					vis.insert(next);
					q.push(next);
				}

			}

			//s-->m
			if (t.s > 0 && t.m < M) {
				if (t.s >= M - t.m) {
					next.s = t.s - (M - t.m);
					next.m = M;
					next.n = t.n;
					next.step = t.step + 1;
				} else {
					next.s = 0;
					next.m = t.s + t.m;
					next.n = t.n;
					next.step = t.step + 1;
				}
				if (vis.find(next) == vis.end()) {
					vis.insert(next);
					q.push(next);
				}
			}

			//n-->s
			if (t.n > 0 && t.s < S) {
				if (t.n >= S - t.s) {
					next.n = t.n - (S - t.s);
					next.s = S;
					next.m = t.m;
					next.step = t.step + 1;
				} else {
					next.n = 0;
					next.s = t.n + t.s;
					next.m = t.m;
					next.step = t.step + 1;
				}
				if (vis.find(next) == vis.end()) {
					vis.insert(next);
					q.push(next);
				}
			}



			//n-->m
			if (t.n > 0 && t.m < M) {
				if (t.n >= M - t.m) {
					next.n = t.n - (M - t.m);
					next.s = t.s;
					next.m = M;
					next.step = t.step + 1;
				} else {
					next.n = 0;
					next.s = t.s;
					next.m = t.m + t.n;
					next.step = t.step + 1;
				}
				if (vis.find(next) == vis.end()) {
					vis.insert(next);
					q.push(next);
				}
			}


			//m-->s
			if (t.m > 0 && t.s < S) {
				if (t.m >= S - t.s) {
					next.m = t.m - (S - t.s);
					next.s = S;
					next.n = t.n;
					next.step = t.step + 1;
				} else {
					next.m = 0;
					next.s = t.s + t.m;
					next.n = t.n;
					next.step = t.step + 1;
				}
				if (vis.find(next) == vis.end()) {
					vis.insert(next);
					q.push(next);
				}
			}

			//m-->n
			if (t.m > 0 && t.n < N) {
				if (t.m >= N - t.n) {
					next.m = t.m - (N - t.n);
					next.s = t.s;
					next.n = N;
					next.step = t.step + 1;
				} else {
					next.m = 0;
					next.s = t.s;
					next.n = t.n + t.m;
					next.step = t.step + 1;
				}
				if (vis.find(next) == vis.end()) {
					vis.insert(next);
					q.push(next);
				}
			}
		}
		if (!flag) {
			printf("NO\n");
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值