zoukankan      html  css  js  c++  java
  • 算法题: 求一个整数数组中,通过元素加减运算得到指定结果的所有运算过程. 例如【5,4,6,7,1】= 9 ?

    题目: 给定一个整数数组int[] a (a.length > 1),和一个整数值 m,试输出所有运算结果等于m的运算过程。可使用的运算方式只有加法和减法。数组元素最多参与一次运算。例如,给定数组【5,4,6,7,1】和整数9,输出运算结果为9的运算过程如下:

    +5+4=9
    +5+4+6-7+1=9
    +5+4-6+7-1=9
    +5-4+7+1=9
    +4+6-1=9
    -4+6+7=9
    -5+6+7+1=9


    这个题目,我们可以使用回溯算法得到所有的解。回溯法在问题的解空间树中,按深度优先策略,从根节点出发搜索解空间树。算法搜索至解空间树中的任一节点时,先判断该节点是否包含问题的解。如果不包含,则跳过对已该结点为根的子数的搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先策略搜索。回溯法求问题所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。回溯法求问题的一个解时,只要搜索到问题的一个解就可结束。

    回溯法通常包含3个步骤

    • 针对所给问题,定义问题的解空间
    • 确定易于搜索的解空间结构。常见的结构一般为n叉树结构,而且一般都是满n叉树。
    • 以深度优先方式搜索解空间,并在搜索过程中使用剪枝函数避免无效搜索。深度优先策略可以选择先序遍历,中序遍历,和后序遍历。

    对于给定的这个题目,我们首先要确定问题的解空间。由于如下的条件限定

    • 运算过程只能使用加法和减法
    • 数组元素最多参与一次运算

    我们可以把数组元素的操作转换为 (x1 * +1 ) + (x2 * -1) + (x3 * 0) ....... = ? ,以题目为例, 容易看出题目需要的解向量为 { (1,1,1,-1,1), (-1,0,1,1,1)..... } ,然后我们可以确定出解空间结构为一个3叉树,而且是一个满三叉树。三叉树深度是给定数组的长度加一,如题中数组长度为5,那么解空间结构的三叉树的深度为6。由于篇幅限制,这里只画了最左部分节点的结构。


    最后,剩下的步骤就是遍历这颗三叉树,检查每个节点的结果是否符合要求。我们以根节点,左子树,中子树,和右子树的顺序进行深度优先遍历。那么以最左边树为例,其遍历的结果如上图所示,其中只有遍历到第三层时的加法运算组合满足要求 (5+4 = 9),那么我们可以得到一个解向量,即 { (1,1,0,0,0) }。另外,符合要求的解,很有可能在叶子结点获得。例如(5+4+6-7+1=9),对应的解向量为{ (1,1,1,-1,1 ) }。

    代码如下

    解空间数据结构的节点类

    package com.csdn.blog.TechNerd.TraceBack;
    /*
     * 构造树节点,包含左子节点,中子节点,和右子节点的引用。以及该节点深度及数据信息。
     */
    public class Node {
    	
    	private Node _lnode;
    	private Node _rnode;
    	private Node _mnode;
    	private int _data;
    	
    	private int _depth;
    	
        public Node(int data,int depth){
        	this._data = data;
        	this._depth = depth;
        }
        
        
        public void setLNode(Node lnode){
        	this._lnode = lnode;
        }
    
        public void setMNode(Node mnode){
        	this._mnode = mnode;
        }
        
        public void setRNode(Node rnode){
        	this._rnode = rnode;
        }
        
    
        
        public int getData(){
        	return this._data;
        }
        
        public int getDepth(){
        	return this._depth;
        }
        
        public Node getLNode(){
        	return this._lnode;
        }
        
        public Node getMNode(){
        	return this._mnode;
        }
        
        public Node getRNode(){
        	return this._rnode;
        }
        
    
        
    }
    


    如下类为解空间数据结构,包含回溯算法的应用。

    package com.csdn.blog.TechNerd.TraceBack;
    
    
    public class TraceBackTree {
    	
    	private Node _root;
    	private int _depth;
    	
    	
    	private int[] _a;  
    	private int _m;   
    	
    	
    	public TraceBackTree(Node root,int depth,int[] a,int m){
    		this._root = root;
    		this._depth = depth;
    		buildBTree();
    		this._a = a;
    		this._m = m;
    	}
    	
       /*
        * 构建解空间数据结构,题目所需要的是一个满三叉树。
        */
    	private void buildBTree(){
    	    
    		this._root.setLNode(createNode(1,2));
    		this._root.setMNode(createNode(0,2));
    		this._root.setRNode(createNode(-1,2));
    		
    	}
    	
    	private Node createNode(int data,int depth){
    		
    		if (depth <= this._depth){
    			Node n = new Node(data,depth);
    			n.setLNode(createNode(1,depth + 1));
    			n.setMNode(createNode(0,depth + 1));
    			n.setRNode(createNode(-1,depth +1));
    			return n;
    		}else{
    			return null;
    		}
    	}
    	
    	/*
    	 * 按照根节点,左子节点,中子节点,右子节点的顺序对数进行遍历,打印所有节点。
    	 */
    	public void preOrderTraverse(){
    		preOrderTraverse(this._root);
    	}
    
    	private void preOrderTraverse(Node n){
    		if (n != null){
    			printNode(n);
    			preOrderTraverse(n.getLNode());
    			preOrderTraverse(n.getMNode());
    			preOrderTraverse(n.getRNode());
    		}
    	}
    	
    	private void printNode(Node n){
    		System.out.print(n.getData() + " ");
    		
    	}
    	/*
    	 *回溯法求所有解。 
    	 */
    	public void backTrace(int[] a,int m){
    
    		int[] x = new int[this._depth - 1]; //定义存储解向量的数组。该数组长度与题目给定的数组长度相等。
            backTrace(this._root,x);
            
    	}
        private void backTrace(Node n,int[] x){
    
           		if (n.getDepth() > 1) x[n.getDepth() - 2] = n.getData(); //将节点值付给解向量数组。
           		
           		if (constraints(x,n.getDepth() - 2)){ 
           			printSolution(x,n.getDepth() - 2);
           		}
           		if (n.getLNode() != null) 
           			backTrace(n.getLNode(),x);
           		if (n.getMNode() != null) 
           			backTrace(n.getMNode(),x);
           		if (n.getRNode() != null) 
           			backTrace(n.getRNode(),x);
           		
        }
    /*
     * 检查目前解向量是否满足题目要求,就和等于指定值。
     */    
    private boolean constraints(int[] x,int boundary) {
    		int sum = 0;
    	    for (int i=0;i<= boundary;i++){
    			sum += _a[i] * x[i]; 
    		}
    	    return (sum == _m && x[boundary] != 0);
    	}
    
    
    	private void printSolution(int[] x,int boundary) {
    		for (int i =0;i<= boundary;i++){
    			if (x[i] == 1){
    				System.out.print("+"+ _a[i]);
    			}else if (x[i] == 0){
    				
    			}else if (x[i] == -1){
    				System.out.print("-" + _a[i]);
    			}
    		}
    		
    		System.out.println("=" + this._m);
    		
    		
    	}
    	
    	public static void main(String[] args){
    		int[] a = {5,4,6,7,1};
    		int m = 9;
    		//创建的数的深度为给定数组的长度加一 
    		TraceBackTree bt = new TraceBackTree(new Node(1,1),a.length + 1,a,m);  
    		//按照根节点,左子节点,中子节点,右子节点的顺序对数进行遍历,打印所有节点。
    		// bt.preOrderTraverse();  
            
            bt.backTrace(a,m);
    	}
    }
    






  • 相关阅读:
    HDU 2899 Strange fuction
    HDU 2899 Strange fuction
    HDU 2199 Can you solve this equation?
    HDU 2199 Can you solve this equation?
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 700 二叉搜索树中的搜索(遍历树)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
    Java实现 LeetCode 699 掉落的方块(线段树?)
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3172158.html
Copyright © 2011-2022 走看看