算法相关,跳棋问题

zhou3968322 2014-04-25 07:04:11
https://img-bbs.csdn.net/upload/201404/22/1398133565_611244.jpg
一共21个洞,20颗棋子(1-20编号)每个棋子跳过另一个棋子进入洞中,就可把另一个棋子拿走。
比如棋子3跳过棋子1进入东中,棋子1被拿走,每一步的规则都是必须跳过一个棋子一走,而且必须
跳进洞中。最后的目标是跳刀只剩一粒棋子。
求遍历出所有可行的跳法。
...全文
237 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhou3968322 2014-04-29
  • 打赏
  • 举报
回复
引用 1 楼 abc130314 的回复:
我算出来有400多亿种走法(43419942138)。 有2个优化方法: 1、可以先把棋盘的状态(有多少棋子,和这些棋子的坐标)缓存起来。下次如果状态一样,就直接从缓存取 2、如果某个时刻棋盘上的棋子是左右对称的,那么也可以跳过一半的计算

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class Main {

	private int width, height;
	private int[][] array;
	private Point[] point;
	private int[][] result;
	private Map<Key, Long> cache = new HashMap<Key, Long>();
	/* 跳的方向
	 *  6 1
	 * 5 0 2
	 *  4 3
	 */
	private int[][] direction = {{1, -1}, {2, 0}, {1, 1}, {-1, 1}, {-2, 0}, {-1, -1}};

	private static class Point {

		public int x, y, value;

		public Point(int x, int y, int value) {
			this.x = x;
			this.y = y;
			this.value = value;
		}
	}

	private static class Key {

		public int[][] point;

		@Override
		public int hashCode() {
			int hash = 5;
			hash = 23 * hash + Arrays.deepHashCode(this.point);
			return hash;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final Key other = (Key) obj;
			if (!Arrays.deepEquals(this.point, other.point)) {
				return false;
			}
			return true;
		}
	}

	public Main(int n) {
		int maxValue = (1 + n) * n / 2 - 1;
		width = n * 2 - 1;
		height = n;
		array = new int[height][width];
		point = new Point[maxValue];
		result = new int[maxValue][2];
		int k = 0;
		for (int y = 0; y < n; y++) {
			Arrays.fill(array[y], -1);
			int s = n - y - 1;
			for (int i = 0; i <= 2 * y; i++) {
				if (i % 2 != 0) {
					array[y][s + i] = 0;
					continue;
				}
				if (k == 0) {
					array[y][s + i] = 0;
				} else {
					array[y][s + i] = k;
					point[k - 1] = new Point(s + i, y, k);
				}
				k++;
			}
		}
		printArray();
	}

	private void printArray() {
		for (int y = 0; y < height; y++) {
			for (int i = 0; i < array[y].length; i++) {
				System.out.format("%2d ", array[y][i]);
			}
			System.out.println();
		}
	}

	public long g() {
		return g(point.length);
	}

	/**
	 * 此时棋盘的形态(依次记录有棋子的格子的坐标)
	 * @param n
	 * @return 
	 */
	private Key buildKey(int n) {
		Key key = new Key();
		key.point = new int[n][2];
		int k = 0;
		for (int i = 0; i < array.length; i++) {
			for (int j = 0; j < array[i].length; j++) {
				if (array[i][j] > 0) {
					key.point[k++] = new int[]{i, j};
				}
			}
		}
		return key;
	}

	private long g(int n) {
		if (n == 1) {
			for (int i = result.length; i > 1; i--) {
				System.out.format("%2d->%2d ", result[i - 1][0], result[i - 1][1]);
			}
			System.out.println("");
			return 1;
		}
		/* 不使用缓存 */
//		if (1 > 0) {
//			return g2(n);
//		}
		Key key = buildKey(n);
		Long total = cache.get(key);
		if (total != null) {
			//System.out.println("hit:" + total);
			return total;
		}
		long s = g2(n);
		cache.put(key, s);
		return s;
	}

	/**
	 * 此时,棋盘是否对称
	 * @return 
	 */
	private boolean isSymmetrical() {
		int center = width / 2;
		for (int y = 0; y < array.length; y++) {
			for (int i = 1; i <= y; i++) {
				int k = 0;
				k += (array[y][center + i] == 0 ? 0 : 1);
				k += (array[y][center - i] == 0 ? 0 : -1);
				if (k != 0) {
					return false;
				}
			}
		}
		return true;
	}

	private long g2(int n) {
		long s = 0;
		/* 此时,棋盘是否对称的*/
//		boolean symmetrical = false;
		boolean symmetrical = isSymmetrical();
		for (int i = 0; i < point.length; i++) {
			Point p = point[i];
			if (p == null) {
				continue;
			}
			int offset = p.x - width / 2;
			//对称的时候,右边的棋子不用计算
			if (symmetrical && offset > 0) {
				continue;
			}
			for (int j = 0; j < direction.length; j++) {
				int x0 = p.x, x1 = p.x + direction[j][0], x2 = p.x + direction[j][0] * 2;
				int y0 = p.y, y1 = p.y + direction[j][1], y2 = p.y + direction[j][1] * 2;
				if (x2 < 0 || x2 >= width || y2 < 0 || y2 >= height
						|| array[y1][x1] == 0 || array[y2][x2] != 0) {
					continue;
				}
				//对称的时候,中间的棋子往右跳不用计算
				if (symmetrical && offset == 0 && direction[j][0] > 0) {
					continue;
				}
				result[n - 1][0] = array[y0][x0];
				result[n - 1][1] = array[y1][x1];
				array[y2][x2] = array[y0][x0];
				p.x = x2;
				p.y = y2;
				array[y0][x0] = 0;
				//
				Point destroyed = point[array[y1][x1] - 1];
				point[array[y1][x1] - 1] = null;
				array[y1][x1] = 0;
				//
				s += g(n - 1);
				//
				array[y1][x1] = destroyed.value;
				point[array[y1][x1] - 1] = destroyed;
				//
				array[y0][x0] = p.value;
				p.x = x0;
				p.y = y0;
				array[y2][x2] = 0;
			}
		}
		return symmetrical ? s * 2 : s;
	}

	public static void main(String[] args) throws Exception {
		long a = System.nanoTime();
		Main m = new Main(6);
		long total = m.g();
		System.out.println("total:" + total);
		long b = System.nanoTime();
		System.out.println("spend:" + TimeUnit.NANOSECONDS.toSeconds(b - a) + "s");
	}
}
万分感谢!!!辛苦了
abc130314 2014-04-25
  • 打赏
  • 举报
回复
我算出来有400多亿种走法(43419942138)。 有2个优化方法: 1、可以先把棋盘的状态(有多少棋子,和这些棋子的坐标)缓存起来。下次如果状态一样,就直接从缓存取 2、如果某个时刻棋盘上的棋子是左右对称的,那么也可以跳过一半的计算

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class Main {

	private int width, height;
	private int[][] array;
	private Point[] point;
	private int[][] result;
	private Map<Key, Long> cache = new HashMap<Key, Long>();
	/* 跳的方向
	 *  6 1
	 * 5 0 2
	 *  4 3
	 */
	private int[][] direction = {{1, -1}, {2, 0}, {1, 1}, {-1, 1}, {-2, 0}, {-1, -1}};

	private static class Point {

		public int x, y, value;

		public Point(int x, int y, int value) {
			this.x = x;
			this.y = y;
			this.value = value;
		}
	}

	private static class Key {

		public int[][] point;

		@Override
		public int hashCode() {
			int hash = 5;
			hash = 23 * hash + Arrays.deepHashCode(this.point);
			return hash;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final Key other = (Key) obj;
			if (!Arrays.deepEquals(this.point, other.point)) {
				return false;
			}
			return true;
		}
	}

	public Main(int n) {
		int maxValue = (1 + n) * n / 2 - 1;
		width = n * 2 - 1;
		height = n;
		array = new int[height][width];
		point = new Point[maxValue];
		result = new int[maxValue][2];
		int k = 0;
		for (int y = 0; y < n; y++) {
			Arrays.fill(array[y], -1);
			int s = n - y - 1;
			for (int i = 0; i <= 2 * y; i++) {
				if (i % 2 != 0) {
					array[y][s + i] = 0;
					continue;
				}
				if (k == 0) {
					array[y][s + i] = 0;
				} else {
					array[y][s + i] = k;
					point[k - 1] = new Point(s + i, y, k);
				}
				k++;
			}
		}
		printArray();
	}

	private void printArray() {
		for (int y = 0; y < height; y++) {
			for (int i = 0; i < array[y].length; i++) {
				System.out.format("%2d ", array[y][i]);
			}
			System.out.println();
		}
	}

	public long g() {
		return g(point.length);
	}

	/**
	 * 此时棋盘的形态(依次记录有棋子的格子的坐标)
	 * @param n
	 * @return 
	 */
	private Key buildKey(int n) {
		Key key = new Key();
		key.point = new int[n][2];
		int k = 0;
		for (int i = 0; i < array.length; i++) {
			for (int j = 0; j < array[i].length; j++) {
				if (array[i][j] > 0) {
					key.point[k++] = new int[]{i, j};
				}
			}
		}
		return key;
	}

	private long g(int n) {
		if (n == 1) {
			for (int i = result.length; i > 1; i--) {
				System.out.format("%2d->%2d ", result[i - 1][0], result[i - 1][1]);
			}
			System.out.println("");
			return 1;
		}
		/* 不使用缓存 */
//		if (1 > 0) {
//			return g2(n);
//		}
		Key key = buildKey(n);
		Long total = cache.get(key);
		if (total != null) {
			//System.out.println("hit:" + total);
			return total;
		}
		long s = g2(n);
		cache.put(key, s);
		return s;
	}

	/**
	 * 此时,棋盘是否对称
	 * @return 
	 */
	private boolean isSymmetrical() {
		int center = width / 2;
		for (int y = 0; y < array.length; y++) {
			for (int i = 1; i <= y; i++) {
				int k = 0;
				k += (array[y][center + i] == 0 ? 0 : 1);
				k += (array[y][center - i] == 0 ? 0 : -1);
				if (k != 0) {
					return false;
				}
			}
		}
		return true;
	}

	private long g2(int n) {
		long s = 0;
		/* 此时,棋盘是否对称的*/
//		boolean symmetrical = false;
		boolean symmetrical = isSymmetrical();
		for (int i = 0; i < point.length; i++) {
			Point p = point[i];
			if (p == null) {
				continue;
			}
			int offset = p.x - width / 2;
			//对称的时候,右边的棋子不用计算
			if (symmetrical && offset > 0) {
				continue;
			}
			for (int j = 0; j < direction.length; j++) {
				int x0 = p.x, x1 = p.x + direction[j][0], x2 = p.x + direction[j][0] * 2;
				int y0 = p.y, y1 = p.y + direction[j][1], y2 = p.y + direction[j][1] * 2;
				if (x2 < 0 || x2 >= width || y2 < 0 || y2 >= height
						|| array[y1][x1] == 0 || array[y2][x2] != 0) {
					continue;
				}
				//对称的时候,中间的棋子往右跳不用计算
				if (symmetrical && offset == 0 && direction[j][0] > 0) {
					continue;
				}
				result[n - 1][0] = array[y0][x0];
				result[n - 1][1] = array[y1][x1];
				array[y2][x2] = array[y0][x0];
				p.x = x2;
				p.y = y2;
				array[y0][x0] = 0;
				//
				Point destroyed = point[array[y1][x1] - 1];
				point[array[y1][x1] - 1] = null;
				array[y1][x1] = 0;
				//
				s += g(n - 1);
				//
				array[y1][x1] = destroyed.value;
				point[array[y1][x1] - 1] = destroyed;
				//
				array[y0][x0] = p.value;
				p.x = x0;
				p.y = y0;
				array[y2][x2] = 0;
			}
		}
		return symmetrical ? s * 2 : s;
	}

	public static void main(String[] args) throws Exception {
		long a = System.nanoTime();
		Main m = new Main(6);
		long total = m.g();
		System.out.println("total:" + total);
		long b = System.nanoTime();
		System.out.println("spend:" + TimeUnit.NANOSECONDS.toSeconds(b - a) + "s");
	}
}

50,503

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧