首页 > 代码库 > 回溯法--符号三角形问题
回溯法--符号三角形问题
问题描述:
如下图是由14个“+”和14个“-”组成的符号三角形, 2个同号下面都是“+”,2个异号下面都是“-”。
- + + - + + +
- + - - + +
- - + - +
+ - - -
- + +
- +
-
在一般情况下,符号三角形的第一行有n个符号, 符号三角形问题要求对于给定的n,
计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。
解题思路:
1、不断改变第一行每个符号,搜索符合条件的解,可以使用递归回溯
为了便于运算,设+ 为0,- 为1,这样可以使用异或运算符表示符号三角形的关系
++为+即0^0=0, --为+即1^1=0, +-为-即0^1=1, -+为-即1^0=1;
2、因为两种符号个数相同,可以对题解树剪枝,
当所有符号总数为奇数时无解,当某种符号超过总数一半时无解
源代码:
#include"iostream"
using namespace std;
typedef unsigned char uchar;
char cc[2]={‘+‘,‘-‘}; //便于输出
int n, //第一行符号总数
half, //全部符号总数一半
counter; //1计数,即“-”号计数
uchar **p; //符号存储空间
long sum; //符合条件的三角形计数
void Backtrace(int t) //t,第一行第t个符号
{
int i, j;
if( t > n )
{//符号填充完毕
sum++;
//打印符号
cout << "第" << sum << "个:\n";
for(i=1; i<=n; ++i)
{
for(j=1; j<i; ++j)
{
cout << " ";
}
for(j=1; j<=n-i+1; ++j)
{
cout << cc[ p[i][j] ] << " ";
}
cout << "\n";
}
}
else
{
for(i=0; i<2; ++i)
{
p[1][t] = i; //第一行第t个符号
counter += i; //“-”号统计,因为"+"的值是0
for(j=2; j<=t; ++j) //当第一行符号>=2时,可以运算出下面行的某些符号,j可代表行号
{
p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];//通过异或运算下行符号,t-j+1确定的很巧
counter += p[j][t-j+1];
}
if( (counter <= half) && ( t*(t+1)/2 - counter <= half) )
{//若符号统计未超过半数,并且另一种符号也未超过半数,同时隐含两者必须相等才能结束
Backtrace(t+1); //在第一行增加下一个符号
}
//回溯,判断另一种符号情况 像是出栈一样,恢复所有对counter的操作
for(j=2; j<=t; ++j)
{
counter -= p[j][t-j+1];
}
counter -= i;
}
}
}
int main()
{
cout << "请输入第一行符号个数n:";
cin >> n;
counter = 0;
sum = 0;
half = n*(n+1)/2;
int i=0;
if( half%2 == 0 )
{//总数须为偶数,若为奇数则无解
half /= 2;
p = new uchar *[n+1];
for(i=0; i<=n; ++i)
{
p[i] = new uchar[n+1];
memset(p[i], 0, sizeof(uchar)*(n+1));
}
Backtrace(1);
for(i=0; i<=n; ++i) //删除二维动态数组的方法
{
delete[] p[i];
}
delete[] p;
}
cout << "\n总共 " << sum << " 个"<< endl;
return 0;
}
回溯法--符号三角形问题