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);
    	}
    }
    






  • 相关阅读:
    Python封装发送信息到钉钉群
    centos 7.6 安装php70
    小米5s plus刷机
    centos 7 安装webmin
    交易开拓者旗舰版(TB旗舰版)软件升级中如何迁移用户数据
    centos 7.6 修改vim配色方案
    centos 7.0 读写ntfs分区
    centos iptables 数据转发
    centos 7.6 配置VNC
    win下maridb 10.1.8下主从复制配置
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3172158.html
Copyright © 2011-2022 走看看