九连环解法java版

之前想写写试试,只写了个开头,最近补完了,试了下跑的还正常。

功能上能指定各个环是否在杆上,可以按拆卸或安装打印解的步骤。


方法两种,都用到了递归,递归的都是为了处理的n个环,需要前n-2个环不在杆,第n-1个环在杆。

方法2里递归直接做了上环下环动作,方法1里递归只是为了找到是否从第一个环开始解。


关于方法1:

九连环解熟了以后,每次只要确定是否从第一个开始解,然后只靠手熟练,不用思考就能解。

分析一下,九连环里任何时刻最多只能有俩动作:一个环上杆、另一个环下杆,选其中一个动作做后,最多还是只有俩动作(解开后就只有一个动作了)。

只要不出现一个环连续重复操作,总会遇到把九连环解开或安装上的时候。

方法1就这个意思。


package com.superzlc.zlctest.game;

public class Jiulianhuan {

	public static void main(String[] args) {
		Jiulianhuan t = new Jiulianhuan();
		//     -999999999-
		t.init("000000009");
		t.print(0);
		t.answer1(true);
		// t.answer2(true);
	}


	// ---------------------
	// 答案1:递归获取从第几个开始解,然后按习惯解。基于任意时刻只能操作最多俩环,每个环只能是上或下
	void answer1(boolean forAllDown) {
		analyse(forAllDown);
		if (!isFind) {
			return;
		}
		Huan start = this.isFirst ? this.getFirstCanChange() : this.getLastCanChange();
		System.out.println("从第" + (start.index + 1) + "开始解");

		while (true) {
			// 任意时刻,都是只能操作最多俩环,每个环只能是上或下
			if (isFirst) {
				this.getFirstCanChange().change();
			} else {
				this.getLastCanChange().change();
			}
			isFirst = !isFirst;

			print(++count);

			if (forAllDown) {
				if (this.isAllDown())
					break;
			} else {
				if (this.isAllUp())
					break;
			}
		}
	}

	private boolean isFind; // 是否找到从第几个开始解
	private boolean isFirst; // 是否从第1个开始解

	// 分析从哪个开始解
	private void analyse(boolean forAllDown) {
		Huan h = this.last;
		if (forAllDown) {
			while (h != null) {
				if (isFind)
					return;
				if (h.isUp()) {
					needChange(h);
				}
				h = h.left;
			}
		} else {
			while (h != null) {
				if (isFind)
					return;
				if (h.isDown()) {
					needChange(h);
				}
				h = h.left;
			}
		}
	}

	// 递归调用获取从哪个开始解
	private void needChange(Huan h) {
		if (isFind)
			return;
		Huan left = h.left;
		if (h.canChange()) {
			isFind = true;
			isFirst = h.isFirst();
			return;
		}
		if (left != null) {
			if (left.isDown()) {
				needChange(left);
			}
			left = left.left;
			while (left != null) {
				if (isFind)
					break;
				if (left.isUp()) {
					needChange(left);
				}
				left = left.left;
			}
		}
	}

	// ---------------------
	// 答案2:递归求解
	void answer2(boolean forAllDown) {
		Huan h = this.last;
		if (forAllDown) {
			while (h != null) {
				if (h.isUp()) {
					execChange(h);
				}
				h = h.left;
			}
		} else {
			while (h != null) {
				if (h.isDown()) {
					execChange(h);
				}
				h = h.left;
			}
		}
	}

	// 递归调用解
	private void execChange(Huan h) {
		Huan left = h.left;
		// 保证能change
		if (left != null) {
			// 左边第一个保证是up的
			if (left.isDown()) {
				execChange(left);
			}
			// 左边更多个保证是down的
			left = left.left;
			while(left != null) {
				if (left.isUp()) {
					execChange(left);
				}
				left = left.left;
			}
		}
		h.change();
		print(++count);
	}

	// ------------------------------------------
	private static final int length = 9;
	private Huan first;
	private Huan last;
	private Huan[] huans;
	private int count = 0;

	Jiulianhuan() {
		huans = new Huan[length];
		for (int i = 0; i < length; i++) {
			huans[i] = new Huan(i, true);
		}
		first = huans[0];
		last = huans[length - 1];
		// link
		for (int i = 0; i < length; i++) {
			Huan left = i - 1 >= 0 ? huans[i - 1] : null;
			Huan right = i + 1 < length ? huans[i + 1] : null;
			huans[i].link(left, right);
		}

	}

	// 以字符串10101101或ududduudu初始化,1/u为up
	void init(String ss) {
		if (ss == null || ss.length() == 0)
			return;
		for (int i = 0; i < length; i++) {
			if (i < ss.length()) {
				char c = ss.charAt(i);
				huans[i].setStatus(c == '1' || c == 'u' || c == '9');
			}
		}
	}

	boolean isAllDown() {
		if (this.first.isUp() || this.last.isUp())
			return false;
		for (Huan t : huans) {
			if (t.isUp())
				return false;
		}
		return true;
	}

	boolean isAllUp() {
		if (this.first.isDown() || this.last.isDown())
			return false;
		for (Huan t : huans) {
			if (t.isDown())
				return false;
		}
		return true;
	}

	Huan getFirstCanChange() {
		// 就是第一个
		return this.first;
	}

	Huan getLastCanChange() {
		// 第k个满足:dddduk
		Huan h = this.first;
		while (h != null) {
			if (h.isUp()) {
				return h.right;
			}
			h = h.right;
		}
		return null;
	}

	void print(int idx) {
		String str1 = idx > 0 ? String.format("%4d: ", idx) : "init: ";
		for (Huan t : huans) {
			if (t.isUp()) {
				str1 += "9";
			} else {
				str1 += "o";
			}
		}
		System.out.println(str1);
	}

	static class Huan {
		public Huan(int index, boolean up) {
			this.index = index;
			this.up = up;
		}

		public void link(Huan left, Huan right) {
			this.left = left;
			this.right = right;
		}

		Huan left;
		Huan right;
		int index;
		boolean up;

		//
		boolean isFirst() {
			return left == null;
		}

		boolean isLast() {
			return right == null;
		}

		//
		boolean canChange() {
			if (isFirst()) {
				// 第一个允许随时能切换
				return true;
			} else {
				// 非第一个k要满足dddduk
				if (left.isDown()) {
					return false;
				}
				Huan t = left.left;
				while (t != null) {
					if (t.isUp()) {
						return false;
					}
					t = t.left;
				}
				return true;
			}
		}

		boolean change() {
			if (canChange()) {
				if (isUp())
					setDown();
				else
					setUp();
				return true;
			} else {
				return false;
			}
		}

		//
		void setUp() {
			setStatus(true);
		}

		void setDown() {
			setStatus(false);
		}

		void setStatus(boolean up) {
			this.up = up;
		}

		boolean isUp() {
			return up;
		}

		boolean isDown() {
			return !isUp();
		}

	}

}


猜你喜欢

转载自blog.csdn.net/superzlc/article/details/68952142
今日推荐