符号三角形问题—回溯算法—java实现

问题描述:

    下图是由14个“+”和14个“-”组成的符号三角形。2个同号下面都是“+”,2个异号下面都是“-”:

                    符号三角形问题—回溯算法—java实现_第1张图片

    符号三角形第一行有n个符号,符号三角形问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。

 

解题思路:

    1、不断改变第一行的每个符号,搜索符合条件的解,可以使用递归回溯。

        为了便于运算,设+ 为0,- 为1,这样可以使用异或运算符表示符号三角形的关系:
            ++为+即0^0=0, --为+即1^1=0, +-为-即0^1=1, -+为-即1^0=1 

    2、因为两种符号个数相同,可以对题解树剪枝

        当所有符号总数为奇数时无解,当某种符号超过总数一半时无解

 

算法设计:

        符号三角形问题—回溯算法—java实现_第2张图片

     在符号三角形的第一行的前i个符号x[1:i]确定后,就确定了一个由i*(i+1)/2个符号组成的符号三角形。

    下一步确定了x[1:i]的值后,只要在前面确定的符号三角形的右边加一条边,就可以扩展为x[1:i]所对应的符号三角形。

    在回溯法搜索过程中可用当前符号三角形所包含的“+”号个数与“-”号个数均不超过n*(n-1)/4作为可行性约束,用于剪去不满足约束条件的子树。

    

 

代码:

    需要的数据:

        static int n;//第一行的符号个数
	static int half;//n*(n+1)/4
	static int count;//当前“+”或者“-”的个数
	static int[][] p;//符号三角形矩阵
	static long sum;//已找到的符号三角形的个数

           

    初始化及计算:

public static float Compute(int nn) {
		n = nn;
		count = 0;
		sum = 0;
		half = (n*(n+1))>>1;
		if((half>>1)<<1 != half) {
			return 0;
		}
		half = half>>1;
		p = new int[n+1][n+1];
		backtrack(1);
		
		return sum;
	}

 

    回溯算法1(仅用于计算行数或者列数为n的符号三角形的总数,没有显示符号三角形的功能,但是是核心代码):

public static void backtrack01(int t) {
		if(count>half || (t*(t-1)/2-count > half)) {//对题解树的剪枝
			return;
		}
		if(t>n) {
			sum++;//符号三角形的总数目+1
		}
		else {
			//每个位置都有两种情况0,1
			for(int i = 0;i<2;i++) {
				p[1][t] = i;
				count += i;//对"-"个数进行技术,为了进行剪枝操作
				
				//接下来绘制其余的n-1行
				for(int j = 2;j<=t;j++) {
					//通过异或的方式求其余行数的放置方式
					p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];
					count += p[j][t-j+1];	
				}
				backtrack01(t+1);
				
				//恢复现场
				for(int j = 2;j<=t;j++) {
					count -= p[j][t-j+1];
				}
				count -= i;
			}
		}
	}

 

    回溯算法2(具备打印符号三角形的功能):

public static void backtrack(int t) {
		if((count>half)||(t*(t-1)/2-count > half)) //对题解树的剪枝
			return;
		if(t>n) {
			sum++;
			//打印符号三角形
			for(int i =1;i<=n;i++) {
				for(int k = 1;k

 

 

 

完整代码:

package tri;

public class TRAN {

	static int n;//第一行的符号个数
	static int half;//n*(n+1)/4
	static int count;//当前“+”或者“-”的个数
	static int[][] p;//符号三角形矩阵
	static long sum;//已找到的符号三角形的个数
	
	public static float Compute(int nn) {
		n = nn;
		count = 0;
		sum = 0;
		half = (n*(n+1))>>1;
		if((half>>1)<<1 != half) {
			return 0;
		}
		half = half>>1;
		p = new int[n+1][n+1];
		backtrack(1);
		
		return sum;
	}
	
	/**
	 * 算法1
	 * @param t
	 */
	/*
	public static void backtrack01(int t) {
		if(count>half || (t*(t-1)/2-count > half) {//对题解树的剪枝
			return;
		}
		if(t>n) {
			sum++;//符号三角形的总数目+1
		}
		else {
			//每个位置都有两种情况0,1
			for(int i = 0;i<2;i++) {
				p[1][t] = i;
				count += i;//对"-"个数进行技术,为了进行剪枝操作
				
				//接下来绘制其余的n-1行
				for(int j = 2;j<=t;j++) {
					//通过异或的方式求其余行数的放置方式
					p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];
					count += p[j][t-j+1];	
				}
				backtrack01(t+1);
				
				//恢复现场
				for(int j = 2;j<=t;j++) {
					count -= p[j][t-j+1];
				}
				count -= i;
			}
		}
	}
	*/
	
	public static void backtrack(int t) {
		if((count>half)||((t*(t-1)/2-count > half)) //对题解树的剪枝
			return;
		if(t>n) {
			sum++;
			//打印符号三角形
			for(int i =1;i<=n;i++) {
				for(int k = 1;k

 

以行数为4的符号三角形为例,显示输出如下:

符号三角形问题—回溯算法—java实现_第3张图片

 

 

你可能感兴趣的:(回溯算法-java实现)