回溯法之符号三角形问题

  1. /*回溯法解符号三角形问题 
  2.  
  3. 问题描述: 
  4. 如下图是由14个“+”和14个“-”组成的符号三角形, 2个同号下面都是“+”,2个异号下面都是“-”。 
  5. - + + - + + +  
  6.  - + - - + +  
  7.   - - + - +  
  8.    + - - -  
  9.     - + +  
  10.      - +  
  11.       - 
  12. 在一般情况下,符号三角形的第一行有n个符号, 符号三角形问题要求对于给定的n, 
  13. 计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。 
  14.  
  15. 解题思路: 
  16. 1、不断改变第一行每个符号,搜索符合条件的解,可以使用递归回溯 
  17. 为了便于运算,设+ 为0,- 为1,这样可以使用异或运算符表示符号三角形的关系 
  18. ++为+即0^0=0, --为+即1^1=0, +-为-即0^1=1, -+为-即1^0=1; 
  19.  
  20. 2、因为两种符号个数相同,可以对题解树剪枝, 
  21. 当所有符号总数为奇数时无解,当某种符号超过总数一半时无解 
  22.  
  23. 参考了学习资料,重新实现以练习,有疏漏之处敬请指正zd163boy@163.com。 
  24. 杨小进,17:13 2009-8-5  
  25. */  
  26. #include"iostream"  
  27. using namespace std;  
  28. typedef unsigned char uchar;  
  29.   
  30. char cc[2]={'+','-'};   //便于输出  
  31. int n,                  //第一行符号总数  
  32.     half,               //全部符号总数一半  
  33.     counter;            //1计数,即“-”号计数  
  34.       
  35. uchar **p;              //符号存储空间      
  36. long sum;               //符合条件的三角形计数  
  37.   
  38. //t,第一行第t个符号  
  39. void Backtrace(int t)  
  40. {  
  41.     int i, j;  
  42.       
  43.     if( t > n )  
  44.     {//符号填充完毕  
  45.         sum++;  
  46.           
  47.         //打印符号  
  48.         cout << "第" << sum << "个:/n";  
  49.         for(i=1; i<=n; ++i)  
  50.         {  
  51.             for(j=1; j<i; ++j)  
  52.             {  
  53.                 cout << " ";  
  54.             }  
  55.               
  56.             for(j=1; j<=n-i+1; ++j)  
  57.             {  
  58.                 cout << cc[ p[i][j] ] << " ";  
  59.             }  
  60.             cout << "/n";  
  61.         }  
  62.     }  
  63.     else  
  64.     {  
  65.        for(i=0; i<2; ++i)  
  66.        {  
  67.             p[1][t] = i;        //第一行第t个符号  
  68.             counter += i;       //“-”号统计  
  69.               
  70.             for(j=2; j<=t; ++j)  //当第一行符号>=2时,可以运算出下面行的某些符号  
  71.             {  
  72.                 p[j][t-j+1] = p[j-1][t-j+1]^p[j-1][t-j+2];//通过异或运算下行符号  
  73.                 counter += p[j][t-j+1];                       
  74.             }  
  75.   
  76.             if( (counter <= half) && ( t*(t+1)/2 - counter <= half) )  
  77.             {//若符号统计未超过半数,并且另一种符号也未超过半数  
  78.                 Backtrace(t+1);         //在第一行增加下一个符号  
  79.             }  
  80.               
  81.             //回溯,判断另一种符号情况  
  82.             for(j=2; j<=t; ++j)    
  83.             {  
  84.                 counter -= p[j][t-j+1];  
  85.             }  
  86.                
  87.             counter -= i;  
  88.        }  
  89.     }  
  90. }  
  91.   
  92. int main()  
  93. {     
  94.     cout << "请输入第一行符号个数n:";  
  95.     cin >> n;  
  96.     counter = 0;  
  97.     sum = 0;  
  98.     half = n*(n+1)/2;  
  99.     int i=0;  
  100.       
  101.     if( half%2 == 0 )  
  102.     {//总数须为偶数,若为奇数则无解  
  103.         half /= 2;  
  104.         p = new uchar *[n+1];  
  105.   
  106.         for(i=0; i<=n; ++i)  
  107.         {  
  108.            p[i] = new uchar[n+1];  
  109.            memset(p[i], 0, sizeof(uchar)*(n+1));  
  110.         }  
  111.              
  112.         Backtrace(1);  
  113.         for(i=0; i<=n; ++i)  
  114.         {  
  115.             delete[] p[i];  
  116.         }  
  117.         delete[] p;  
  118.     }  
  119.       
  120.     cout << "/n总共 " << sum << " 个"<< endl;  
  121.     return 0;  
  122. }  
posted @ 2014-12-04 19:31  IT下载  阅读(452)  评论(0编辑  收藏  举报