【11回溯法-符号三角形问题】
问题描述:
给定一个数字n,求出符合符号三角形的三角形个数,符号三角形的定义为:
由+ - 符号构成的倒三角形,同号下方为+,异号下方为-,且+号数量=-号数量的三角形。
问题分析:
1 该三角形每行个数依次递减,所以总数是等差数列,S = (1+n)*n/2。
2 三角形的总数S一定为偶数。
3 正负符号的个数一定为S/2。(可行解)
4 每个部分符号三角形一定满足:正或负符号个数<S/2。(剪枝函数)
算法分析
1 首先,分析如果单纯构成全为+的符号三角形如何用递归构成。方法为每次在原来三角形基础上新增一条(斜)边。此过程通过递归解决。
2 然后分析递归传递的参数。由于新增的边符号集合由(该边的第一个符号)第一行的符号决定,因此对第一行的第t个符号进行递归。
3 然后分析剪枝函数,由于存在部分三角形的正负符号>S/2的情况,在此情况下(正号 >half ||负号>half )无需再新增边计算最终三角形,因此需要对该边进行剪枝操作(return),即更换该边对应的第一行符号,重新生成斜边。
4 生成结果。当一次递归进行到第一行的第n个数时(最后一条边),且没有被剪枝,则生成一个符号三角形,sum++。
符号三角形问题算法:
void triangle(int t){//第一行第t个符号
if(count > half || t(t-2)/2 > half) //half是三角形总数的一半
return;
if(t>n){//一轮递归完,生成一个符号三角形且没有被剪枝
sum++;
}else{//一轮没有递归完,继续进行新边的递归
for(i=0;i<2;i++){//第一行第i个符号有两个选择,0或者1,0为+,1为-
p[1][t] = i;
count+=i;//count为-号的个数
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];
}
triangle(t+1);
for(j=2;j<=t;j++)//当回溯到t处后,负号的数量也要回溯。
count-=p[j][t-j+1];
}
count-=i;
}