NYOJ--21(搜索)-题目-----------------------------三个水杯

package search;

/*三个水杯

 时间限制:1000 ms  |  内存限制:65535 KB

 描述
 给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子。
 三个水杯之间相互倒水,并且水杯没有标识,只能根据给出的水杯体积来计算。
 现在要求你写出一个程序,使其输出使初始状态到达目标状态的最少次数。

 输入
 第一行一个整数N(0<N<50)表示N组测试数据
 接下来每组测试数据有两行,第一行给出三个整数V1 V2 V3 (V1>V2>V3 V1<100 V3>0)表示三个水杯的体积。
 第二行给出三个整数E1 E2 E3 (体积小于等于相应水杯体积)表示我们需要的最终状态

 输出
 每行输出相应测试数据最少的倒水次数。如果达不到目标状态输出-1
 样例输入
 2
 6 3 1
 4 1 1
 9 3 2
 7 1 1
 样例输出
 3
 -1

 我的思路:这道题和我做的拿到泊松分酒感觉挺像的,但是我那样做,不能保证是最少次数的,然后又用深搜,不知道为什么一直内存益处;
 最后实在不知道咋办,就找度娘,看了一大神(http://blog.csdn.net/jcjc918/article/details/9336785)的思路,然后我用java做出来了。用广搜。
 首先杯子有三个:a , b ,c;
 1,先将杯子a放进队列,在bfs()里,出队,那么a可以给b或者c倒水,那就分别都倒水
 2,上一步完成之后,就将b和c的状态入队,同时用一个数组记录那个状态出现过了就为true
 3,不断重复1,2步骤,直到队列为空为止,请看代码。

 */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.Arrays;
import java.util.LinkedList;

public class search_21 {

	// 创建一个杯子类
	public static class Cup {
		int a, b, c, count;

		public Cup() {
		}

		public Cup(int a, int b, int c) {
			this.a = a;
			this.b = b;
			this.c = c;
		}
	}

	private static int v1 = 0, v2 = 0, v3 = 0, e1 = 0, e2 = 0, e3 = 0;// 一开始输入的杯子体积和目标状态
	private static LinkedList<Cup> cups = new LinkedList<Cup>();// 队列
	private static boolean[][][] visited = new boolean[101][101][101];// 记录杯子出现过的状态
	private static Cup start, cup;
	private static boolean has;// 判断是否有可能达到目标状态

	public static void main(String[] args) {
		Scanner sc = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
		int n = sc.nextInt();

		while (n-- > 0) {

			// 这里是初始化,因为题目要求可一次同时测试多组数据
			cups.clear();
			for (int i = 0; i < 101; i++)
				for (int j = 0; j < 101; j++)
					Arrays.fill(visited[i][j], false);
			has = false;

			v1 = sc.nextInt();
			v2 = sc.nextInt();
			v3 = sc.nextInt();
			e1 = sc.nextInt();
			e2 = sc.nextInt();
			e3 = sc.nextInt();

			start = new Cup(v1, 0, 0);
			visited[v1][0][0] = true;
			cups.add(start);// 将初始状态入队
			bfs();// 广搜
			if (!has)
				System.out.println(-1);
		}
		sc.close();
	}

	private static void bfs() {

		while (!cups.isEmpty()) {

			cup = cups.remove();// 出队

			// System.out.println(cup.a + " " + cup.b + " " +
			// cup.c);//打印过程
			// 如果达到目标
			if (cup.a == e1 && cup.b == e2 && cup.c == e3) {
				System.out.println(cup.count);
				has = true;
				break;
			}

			// 如果杯子a有水,而杯子b的水没有符合目标要求,那么a倒水给b
			if (cup.a != 0 && cup.b < v2) {
				Cup tmp = new Cup();
				// 如果a的水+b的水比b的水杯体积还大,那么a杯子有剩
				if (cup.a + cup.b > v2)
					tmp.a = cup.a + cup.b - v2;
				else
					tmp.a = 0;
				// 那么b杯子有a倒过来的水( cup.a - tmp.a )+可能自己原本也有的水(cup.b)
				tmp.b = cup.a - tmp.a + cup.b;
				tmp.c = cup.c;
				tmp.count = cup.count + 1;// 更新次数
				// 标记状态
				if (!visited[tmp.a][tmp.b][tmp.c]) {
					visited[tmp.a][tmp.b][tmp.c] = true;
					cups.add(tmp);
				}
			}

			//下面一样的道理
			//a→c
			if (cup.a != 0 && cup.c < v3) {
				Cup tmp = new Cup();
				if (cup.a + cup.c > v3)
					tmp.a = cup.a + cup.c - v3;
				else
					tmp.a = 0;
				tmp.c = cup.a - tmp.a + cup.c;
				tmp.b = cup.b;
				tmp.count = cup.count + 1;
				if (!visited[tmp.a][tmp.b][tmp.c]) {
					visited[tmp.a][tmp.b][tmp.c] = true;
					cups.add(tmp);
				}
			}

			//b→a
			if (cup.b != 0 && cup.a < v1) {
				Cup tmp = new Cup();
				if (cup.b + cup.a > v1)
					tmp.b = cup.b + cup.a - v1;
				else
					tmp.b = 0;
				tmp.a = cup.b - tmp.b + cup.a;
				tmp.c = cup.c;
				tmp.count = cup.count + 1;
				if (!visited[tmp.a][tmp.b][tmp.c]) {
					visited[tmp.a][tmp.b][tmp.c] = true;
					cups.add(tmp);
				}
			}

			//b→c
			if (cup.b != 0 && cup.c < v3) {
				Cup tmp = new Cup();
				if (cup.b + cup.c > v3)
					tmp.b = cup.b + cup.c - v3;
				else
					tmp.b = 0;
				tmp.c = cup.b - tmp.b + cup.c;
				tmp.a = cup.a;
				tmp.count = cup.count + 1;
				if (!visited[tmp.a][tmp.b][tmp.c]) {
					visited[tmp.a][tmp.b][tmp.c] = true;
					cups.add(tmp);
				}
			}

			//c→a
			if (cup.c != 0 && cup.a < v1) {
				Cup tmp = new Cup();
				if (cup.c + cup.a > v1)
					tmp.c = cup.c + cup.a - v1;
				else
					tmp.c = 0;
				tmp.a = cup.c - tmp.c + cup.a;
				tmp.b = cup.b;
				tmp.count = cup.count + 1;
				if (!visited[tmp.a][tmp.b][tmp.c]) {
					visited[tmp.a][tmp.b][tmp.c] = true;
					cups.add(tmp);
				}
			}

			//c→b
			if (cup.c != 0 && cup.b < v2) {
				Cup tmp = new Cup();
				if (cup.c + cup.b > v2)
					tmp.c = cup.c + cup.b - v2;
				else
					tmp.c = 0;
				tmp.b = cup.c - tmp.c + cup.b;
				tmp.a = cup.a;
				tmp.count = cup.count + 1;
				if (!visited[tmp.a][tmp.b][tmp.c]) {
					visited[tmp.a][tmp.b][tmp.c] = true;
					cups.add(tmp);
				}
			}
		}
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值