趣味迷宫 F(2011) = 2012 , 从2011走到2012


如上图,入口2011,经过加减乘除后到达出口2012。

规则:1、不能连续执行两次操作;2、方向必须”向前“。

具体例子:从/2到*3后,只能执行-5,不能掉头执行/2或者+7(规则2),更加不能够再次*3(规则1)


在微博 http://weibo.com/1915548291/z4eTPtAnv 发现此问题。此微博的评论有其他同学更高效的算法(A*算法、双向BFS etc.),有兴趣请点击~

问题源于 http://www2.stetson.edu/~efriedma/holiday/2011/index.html

在Matrix67的博客有介绍 http://www.matrix67.com/blog/archives/4790


基本思路:使用BFS或者DFS搜索以2011为根的树即可。

另外:1、根据规则2,必须要处理好计算的方向问题:例如 *3后有可能从左侧进入-5,也有可能从右侧。

    2、注意到 2012不能被3整除,所以唯一的可能的最后操作就是 “左侧进入”的 *3  或者 +7 或者 /2 之后的-5。

    3、进行简单的重复状态判定。为了简便起见,这里仅判定 数值+操作 是否重复了:对这两个因子做简单的哈希处理即可。

======================

枚举 操作+方向:

private  enum OperationAndDirection {
		 START(0),
		 ADD7_LEFT(1),ADD7_RIGHT(2),
		 SUB5_LEFT(3),SUB5_RIGHT(4), // SUB5_RIGHT is the ONLY OandD that leads to the exit 2012.
		 MUL3_LEFT(5),MUL3_RIGHT(6),
		 DIV2_LEFT(7),DIV2_RIGHT(8);
		 
		public final int value;

		OperationAndDirection(int value) {
			this.value = value;
		}
	}

=====================

内部类Node 及 其他数据结构:

	private Queue<Node> q = new LinkedList<Node>(); // used in BFS
	private Set<Integer> values = new HashSet<Integer>();
	// Keep track of the number of visited nodes.
	private long visitedNodes = 0;
	// Keep track of the number of solutions within 30 levels of DFS tree.
	private int solutions= 0;
	
	
	private class Node{
		public int value;
		public OperationAndDirection od;
		public Node parent;
		public Node(int v,OperationAndDirection od,Node p){
			this.value = v;
			this.parent = p;
			this.od = od;
		}


		@Override
		public String toString() {
			return value+":"+od;
		}

		@Override
		public boolean equals(Object obj) {
			return this.value == ((Node)obj).value && this.od == ((Node)obj).od;
		}

		@Override
		public int hashCode() {
			return this.value*10 + this.value + this.od.value;
		}
	}


======================

使用BFS求解:

private void addOrNot(Node n){
		if(!values.contains(n.hashCode())){
			values.add(n.hashCode());
			q.add(n);
			visitedNodes++;
		}
	}
	
	// A simple solution is as follows:
	// Use BFS to generate numbers on each level, and  test whether a number is 2012,
	// and the number is calculated either by *3 or -5.
	// In this case, because 2012 cannot be divided by 3,
	// thus only subtracting 5 is a valid operation. That is, the final calculation should be 2017 - 5 = 2012
	// Also notice that -5 should be a from-left-to-right operation.
	// That is, after -5, the direction is going to the exit, not going back to the entrance.
	public void compute(int entrance,int exit){
		Node start = new Node(entrance,OperationAndDirection.START,null);
		Node n1 = new Node(entrance+7,OperationAndDirection.ADD7_RIGHT,start);
		Node n2 = new Node(entrance/2,OperationAndDirection.DIV2_RIGHT,start);
		addOrNot(start);
		addOrNot(n1);
		addOrNot(n2);
		
		// BFS
		while(!q.isEmpty()){
			Node n = q.poll();
			int p = n.value;
			if (n.value == exit && n.od == OperationAndDirection.SUB5_RIGHT){
				Stack<OperationAndDirection> operations = new Stack<OperationAndDirection>();
				while(n.parent!=null){
					operations.push(n.od);
					n = n.parent;
				}
				System.out.print(entrance);

				while(!operations.empty()) {
					OperationAndDirection op = operations.pop();
					if(op == OperationAndDirection.ADD7_LEFT || op == OperationAndDirection.ADD7_RIGHT){
						System.out.print(" +7");
					}else if(op == OperationAndDirection.SUB5_LEFT || op == OperationAndDirection.SUB5_RIGHT){
						System.out.print(" -5");
					}else if(op == OperationAndDirection.MUL3_LEFT || op == OperationAndDirection.MUL3_RIGHT){
						System.out.print(" *3");
					}else if(op == OperationAndDirection.DIV2_LEFT || op == OperationAndDirection.DIV2_RIGHT){
						System.out.print(" /2");
					}
				}
				System.out.println(" = " + exit);
				System.out.println(visitedNodes + " nodes were visited.");
				return;
			}
			switch (n.od) {
			case SUB5_RIGHT:
				addOrNot(new Node(p*3,OperationAndDirection.MUL3_LEFT,n));
				break;
			case SUB5_LEFT:
				addOrNot(new Node(p+7,OperationAndDirection.ADD7_LEFT,n));
				addOrNot(new Node(p/2,OperationAndDirection.DIV2_LEFT,n));
				addOrNot(new Node(p*3,OperationAndDirection.MUL3_RIGHT,n));
				break;
			case ADD7_RIGHT:
				addOrNot(new Node(p-5,OperationAndDirection.SUB5_RIGHT,n));
				addOrNot(new Node(p/2,OperationAndDirection.DIV2_LEFT,n));
				addOrNot(new Node(p*3,OperationAndDirection.MUL3_RIGHT,n));
				break;
			case ADD7_LEFT:
				addOrNot(new Node(p/2,OperationAndDirection.DIV2_RIGHT,n));
				break;
			case MUL3_RIGHT:
				addOrNot( new Node(p-5,OperationAndDirection.SUB5_LEFT,n));
				break;
			case MUL3_LEFT:
				addOrNot(new Node(p+7,OperationAndDirection.ADD7_LEFT,n));
				addOrNot(new Node(p-5,OperationAndDirection.SUB5_RIGHT,n));
				addOrNot(new Node(p/2,OperationAndDirection.DIV2_LEFT,n));
				break;
			case DIV2_RIGHT:
				addOrNot(new Node(p+7,OperationAndDirection.ADD7_LEFT,n));
				addOrNot(new Node(p-5,OperationAndDirection.SUB5_RIGHT,n));
				addOrNot(new Node(p*3,OperationAndDirection.MUL3_RIGHT,n));
				break;
			case DIV2_LEFT:
				addOrNot(new Node(p+7,OperationAndDirection.ADD7_RIGHT,n));
				break;
			default:
				break;
			}
		}
	}

====================

使用DFS求解:

1、注意这里限定了搜索深度为40

2、在每层搜索完毕删除该结点在哈希表中的值,以输出其他解

public From2011To2012_SimpleDFS(int en, int ex) {
		this.entrance = en;
		this.exit = ex;
	}

	private void dfsOrNot(Node n,int level){
		if(!values.contains(n.hashCode())){
			values.add(n.hashCode());
			dfs(n,level);
			values.remove(n.hashCode());
		}
	}
	
	private void dfs(Node n, int level){
		visitedNodes++;
		if (n.value == exit && n.od == OperationAndDirection.SUB5_RIGHT){
			solutions++;
			Stack<OperationAndDirection> operations = new Stack<OperationAndDirection>();
			while(n.parent!=null){
				operations.push(n.od);
				n = n.parent;
			}
			System.out.print(this.entrance);

			while(!operations.empty()) {
				OperationAndDirection op = operations.pop();
				if(op == OperationAndDirection.ADD7_LEFT || op == OperationAndDirection.ADD7_RIGHT){
					System.out.print(" +7");
				}else if(op == OperationAndDirection.SUB5_LEFT || op == OperationAndDirection.SUB5_RIGHT){
					System.out.print(" -5");
				}else if(op == OperationAndDirection.MUL3_LEFT || op == OperationAndDirection.MUL3_RIGHT){
					System.out.print(" *3");
				}else if(op == OperationAndDirection.DIV2_LEFT || op == OperationAndDirection.DIV2_RIGHT){
					System.out.print(" /2");
				}
			}
			System.out.println(" = " + this.exit);
		}
		
		if(level == 40){
			return;
		}else{
			int p = n.value;
			switch (n.od) {
			case START:
				dfsOrNot(new Node(entrance+7,OperationAndDirection.ADD7_RIGHT,n),level+1);
				dfsOrNot(new Node(entrance/2,OperationAndDirection.DIV2_RIGHT,n),level+1);
				break;
			case SUB5_RIGHT:
				dfsOrNot(new Node(p*3,OperationAndDirection.MUL3_LEFT,n),level+1);
				break;
			case SUB5_LEFT:
				dfsOrNot(new Node(p+7,OperationAndDirection.ADD7_LEFT,n),level+1);
				dfsOrNot(new Node(p/2,OperationAndDirection.DIV2_LEFT,n),level+1);
				dfsOrNot(new Node(p*3,OperationAndDirection.MUL3_RIGHT,n),level+1);
				break;
			case ADD7_RIGHT:
				dfsOrNot(new Node(p-5,OperationAndDirection.SUB5_RIGHT,n),level+1);
				dfsOrNot(new Node(p/2,OperationAndDirection.DIV2_LEFT,n),level+1);
				dfsOrNot(new Node(p*3,OperationAndDirection.MUL3_RIGHT,n),level+1);
				break;
			case ADD7_LEFT:
				dfsOrNot(new Node(p/2,OperationAndDirection.DIV2_RIGHT,n),level+1);
				break;
			case MUL3_RIGHT:
				dfsOrNot( new Node(p-5,OperationAndDirection.SUB5_LEFT,n),level+1);
				break;
			case MUL3_LEFT:
				dfsOrNot(new Node(p+7,OperationAndDirection.ADD7_LEFT,n),level+1);
				dfsOrNot(new Node(p-5,OperationAndDirection.SUB5_RIGHT,n),level+1);
				dfsOrNot(new Node(p/2,OperationAndDirection.DIV2_LEFT,n),level+1);
				break;
			case DIV2_RIGHT:
				dfsOrNot(new Node(p+7,OperationAndDirection.ADD7_LEFT,n),level+1);
				dfsOrNot(new Node(p-5,OperationAndDirection.SUB5_RIGHT,n),level+1);
				dfsOrNot(new Node(p*3,OperationAndDirection.MUL3_RIGHT,n),level+1);
				break;
			case DIV2_LEFT:
				dfsOrNot(new Node(p+7,OperationAndDirection.ADD7_RIGHT,n),level+1);
				break;
			default:
				break;
			}
		}
	}
	
	
	public void compute(){
		Node start = new Node(this.entrance,OperationAndDirection.START,null);
		dfs(start,1);
		System.out.println(visitedNodes + " nodes were visited.");
		System.out.println(solutions + " solutions.");
	}


BFS找到了最优解(执行了26次计算)如下:

2011 /2 +7 /2 +7 /2 +7 /2 +7 /2 *3 -5 *3 -5 +7 /2 -5 *3 -5 *3 /2 +7 -5 *3 /2 +7 -5 = 2012


而对于DFS,限定搜索深度为30层的结果如下:

28681973 nodes were visited.
212 solutions.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值