回溯法之符号三角形问题
问题描述:
由14个“+”号和14个“-”号组成的符号三角形。
2个同号下面是“+”号,2个异号下面是“-”号。
如图:
+ + _ + _ + +
+ _ _ _ _ +
_ + + + _
_ + + _
_ + _
_ _
+
在一般情况下,符号三角形第一行有N个符号,该问题要求对于给定n计算有多少种不同的符号三角形。使其所含的+ — 个数相同。
算法设计:
1 x[i] =1 时,符号三角形的第一行的第i个符号为+
2 x[i] =0时,表示符号三角形的第一行的第i个符号位-
共有i(i+1)/2个符号组成的符号三角形。
3 确定x[i+1]的值后,只要在前面确定的符号三角形的右边加一条边就扩展为x[1:i+1]所相应的符号三角形。
4 最后三角形中包含的“+”“-”的个数都为i(i+1)/4,因此搜索时,个数不能超过i(i+1)/4,若超直接可以剪去分枝。
5 当给定的n(n+1)/2为奇数时,也不符合三角形要求。
算法实现:
#include <stdio.h> #include <conio.h> #define MAX 100 //global variables int count=0;//the number of '-' int sum=0;//the number of the result int p[MAX][MAX]={0}; //1 is '-' 0 is '+' int n=0; int half=0;//half=n*(n+1)/4 void back_triangle(int t); int main() { printf("Please input n:"); scanf("%d",&n); half=n*(n+1)/2; if(half%2!=0) { printf("The number that you input is not meaningful for this problem!"); getch(); return 1; } half/=2; back_triangle(1); printf("The result is %d",sum); getch(); return 0; } void back_triangle(int t) { if(count>half || t*(t-1)/2-count>half)//because of this,the "count==half" is not necessary return ; if(t>n) //the count==half is not necessary { sum++; for(int temp=1;temp<=n;temp++) { for(int tp=1;tp<=n;tp++) { printf("%d ",p[temp][tp]); } printf("\n"); } printf("\n"); } else { int i; for(i=0;i<2;i++) { p[1][t]=i; count+=i; int j; for(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]; } back_triangle(t+1); for(j=2;j<=t;j++) count-=p[j][t-j+1]; count-=i; } } }
运行结果:
下面是n*(n+1)/2为奇数时的结果;
算法效率分析
计算可行性约束需要O(n)时间,在最坏情况下有O(2^n)个结点需要计算可行性约束,故总计算时间为O(n*2^n)
参考:王晓东《算法设计分析》
https://www.cnblogs.com/xing901022/archive/2012/10/23/2735058.html