回溯法之符号三角形问题
- /*回溯法解符号三角形问题
- 问题描述:
- 如下图是由14个“+”和14个“-”组成的符号三角形, 2个同号下面都是“+”,2个异号下面都是“-”。
- - + + - + + +
- - + - - + +
- - - + - +
- + - - -
- - + +
- - +
- -
- 在一般情况下,符号三角形的第一行有n个符号, 符号三角形问题要求对于给定的n,
- 计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。
- 解题思路:
- 1、不断改变第一行每个符号,搜索符合条件的解,可以使用递归回溯
- 为了便于运算,设+ 为0,- 为1,这样可以使用异或运算符表示符号三角形的关系
- ++为+即0^0=0, --为+即1^1=0, +-为-即0^1=1, -+为-即1^0=1;
- 2、因为两种符号个数相同,可以对题解树剪枝,
- 当所有符号总数为奇数时无解,当某种符号超过总数一半时无解
- 参考了学习资料,重新实现以练习,有疏漏之处敬请指正zd163boy@163.com。
- 杨小进,17:13 2009-8-5
- */
- #include"iostream"
- using namespace std;
- typedef unsigned char uchar;
- char cc[2]={'+','-'}; //便于输出
- int n, //第一行符号总数
- half, //全部符号总数一半
- counter; //1计数,即“-”号计数
- uchar **p; //符号存储空间
- long sum; //符合条件的三角形计数
- //t,第一行第t个符号
- void Backtrace(int 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; //“-”号统计
- for(j=2; j<=t; ++j) //当第一行符号>=2时,可以运算出下面行的某些符号
- {
- p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];//通过异或运算下行符号
- counter += p[j][t-j+1];
- }
- if( (counter <= half) && ( t*(t+1)/2 - counter <= half) )
- {//若符号统计未超过半数,并且另一种符号也未超过半数
- Backtrace(t+1); //在第一行增加下一个符号
- }
- //回溯,判断另一种符号情况
- 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;
- }