符号三角形问题逻辑分析与代码设计

题目介绍:

如下图是由14个 “+” 和14个 “-” 组成的符号三角形, 2个同号下面都是 “+”,2个异号下面都是 “-”。 
-   +    +    -    +    +    +  
  -    +    -     -    +    +  
    -     -     +    -    +  
       +    -     -     -  
          -     +    +  
             -     +  
                 - 
在一般情况下,符号三角形的第一行有n个符号, 符号三角形问题要求对于给定的n, 
计算有多少个不同的符号三角形(一整个算一个,而不是在大三角形中间扣小三角),使其所含的 “+” 和 “-” 的个数相同。

先上代码:

#include <iostream>
using namespace std;

//函数 参数的声明
class Triangle
{
    friend int Compute(int);
private:
    void Backtrack(int t);  //回溯函数
    int n,    //第一行的符号数
    half,     //总三角形一半的符号数(n*(n+1)/4)     
    jiahao,   //加号个数    
    **p;      //可以理解为一个二维数组,反正我是这么理解的
    long sum; //计数器
};
 

//回溯函数的编写
void Triangle::Backtrack(int t)
{
    if((jiahao > half) || (t*(t-1)/2-jiahao > half)){
    	return;
	}  /*加号超出总数的一半,或者减号超出总数的一半直接回溯。注意:这里计算的是已经遍
       历的符号三角形的加号减号个数,t的值是+1后的值,所以用t*(t-1)/2而不是t*(t+1)/2*/

    if(t > n){
    	sum++;
	}  //已经遍历完了第一行的n个符号,说明这个三角形符合条件,计数器+1
    else{
        for(int i=0; i<2; i++)//两次循环,i=0减号,i=1加号
        {
            p[1][t] = i;//第一行第t个符号赋值
            jiahao += i;//计算加号个数,因为减号i=0,所以都加不影响。
            for(int j = 2; j <= t; j++)/*在第一行添加符号后,将确定好的部分全部赋值,其实也就是最右边的那一列*/
            {
                p[j][t-j+1] = p[j-1][t-j+1] ^ p[j-1][t-j+2];/*这就是同或语句,你也可以自己写一个函数来实现(都是0或1返回1,一个1一个0返回0)*/
                jiahao += p[j][t-j+1]; //计算“+”个数
            }
            Backtrack(t+1);//添加下一个符号
            for(int j=2; j<=t; j++){  /*回溯回来以后也需要将符号的统计回溯,减去新添加的那一列符号个数*/
                jiahao -= p[j][t-j+1];
            }
            jiahao-=i; //更换符号的时候也需要减去本身的那个符号
        }
    }
}


//主要函数,不是主函数
int Compute(int n)
{
    Triangle X;
    X.n=n;       
    X.jiahao=0;
    X.sum=0;
    X.half=n*(n+1)/2; //这几行看不懂建议回炉重造,基本已是废人一个了
    if(X.half%2==1){
    	return 0;
	} //先要判断总符号数是否为奇数,奇数直接舍弃
    X.half=X.half/2;
 
    int **p=new int *[n+1];  /*相当于二维数组定义a[i][j]中i的长度(行数),因为不想用a[0]那个位置,直接从a[1]开始用,所以定义的是n+1,而不是n。*/
    for(int i=0; i<=n; i++)
        p[i]=new int[n+1];   //相当于二维数组定义a[i][j]中j的长度(列数)     
 
    for(int i=0; i<=n; i++)
        for(int j=0; j<=n; j++)
            p[i][j]=0;       //两个循环,整个矩阵全部初始化为0,相当于全是减号
    X.p=p;                   
    X.Backtrack(1);          //进入回溯
    return X.sum;
}
int main()//这才是主函数
{
 
    int n,result; //n是第一行的符号个数,result结果
    cout<<"输入第一行符号的个数(n的值):"<<endl;
    while(cin>>n)//循环输入,方便测试,使用的时候可去掉。
    {
        ans=Compute(n);
        cout<<result<<endl;
    }
    int nice = 0;
    return nice;
}

问题分析:

观察整个符号三角形,结合“ 2个同号下面都是 ‘+’,2个异号下面都是 ‘-’ ”这句话,我们可以知道的是,只要确定了第一行的符号类型,那么下面所有行的符号类型就可以唯一确定。

也就是说,我们只要对第一行进行分析就可以了。在这里,我准备采用从左向右逐渐一个一个符号的添加的方式来考虑。这样,只要确定了第一行连续的几个符号的类型,就可以确定下面所有符号的类型,一旦有确定的东西,就可以对其展开计算。

算法设计:

先判断n,因为总符号数如果为奇数,肯定不符合要求。

然后,从第一行的第一个符号开始,逐个添加符号(先添加减号,回溯回来后再添加加号),每添加一个符号,就要进行以下操作:

1、计算加号的个数,判断是否满足不超过总数(最终那个n层符号三角形的符号个数,而不是已遍历的符号个数)的一半的条件。再通过加号个数确定减号个数,做出相似判断。

2、符合条件则继续添加,不符合则回溯到上一级(此时还需将符号的计数也回溯),更换为“+”继续添加,并做判断。

3、如果已经添加到超出n的时候,就可以将此时的情况记录下来,因为只有前n个符号满足条件才能超出。

算法详细设计:

请返回顶端看代码。

废话文学:

n的最小值是3。

n>=3时,第一行全“+”或全“-”的情况并不是都能舍去,只有n=3时,全“-”不能舍去。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值