回溯法-符号三角形

问题描述:如下图所示,由14个‘+’和14个'-'号组成的符号三角形。2个同号下面是'+',2个异号下面是‘-’号。

在一般情况下,符号三角形的第一行有n个符号。求:给定的n,计算有多少个不同的符号三角形,使其所含的'+'和'-'的个数相同。


问题分析

回溯法的经典的两种解空间树:子集树(从集合中选取特定的子集)和排列树(组合排列)。此题也属于组合排列问题,由于此题需要统计‘+’号和'-'号的个数,因此需要存储每种情况下的中间结果。注意到当我们确定了第一行第i个符号后,我们可以很快得到第i+1个符号的结果,此时第i+1个符号或者为‘-’,或者为‘+’,当i = n时,即为所求结果。

为了加速处理,这里当第i位为‘+’时,x[i] = 0,否则x[i] = 1。为什么这么设置呢?因为题目中“2个同号下面是'+',2个异号下面是‘-’号”这正是异或运算的性质哦,这样程序中的判断两个符号是否一致就可以采用异或运算,加快处理。

采用回溯法,还要注意限界函数的设计。由于符号三角形的每行之间相差1,是一个等差数列,所以符号三角形的总符号数为n*(n + 1)/2,并且要求'+'和'-'号的个数相等,所以'+'和‘-’号的个数均为n*(n + 1) / 4。因此当'+‘或'-'的个数大于n*(n + 1) / 4时,则停止并返回。最后n* (n + 1)/2必须为偶数,当为奇数时,‘+’和‘-’号的个数必不相等。

源码

struct tag_Triangle

{

int count; //‘+’号个数

int ** sym;//符号三角形矩阵

        int sum; //已找到符合条件的三角形数

};


void GetTriangleSum(int cur,int n,int half,struct tag_Triangle* tri)

{

//条件检测

if(!tri || tri->count > half / 2 || half - tri->count > half) return ;

if( cur > n) tri->sum ++;

else

{

for(int i = 0; i < 2; ++i)

{

tri->sym[1][cur] = i;

tri->count += i;

for(int j = 2; j <= cur; ++ j)

{

p[j][cur - j + 1]  =  p[j - 1][cur - j + 1] ^ p[j - 1][cur - j + 2];

tri->count += p[j][cur- j + 1];

}

GetTriangleSum(cur + 1,n,half,tri);

for(int j = 2; j <= cur; ++j)

{

tri->count -= p[j][cur - j + 1];

}

tri->count -= i;

}

}


void Init(int n)

{

if(n <= 0 ) return ;

int half =  n * (n + 1) / 2;

if( half & 0x01) return ;

struct tag_Triangle* tri = (struct tag_Triangle*)malloc(sizeof(struct tag_Triangle));

if(!tri) return ;

tri->sym = (int**)malloc(sizeof(int*) * (n + 1));

for(int i = 0; i <= n; ++i)

{

tri->sym[i] = (int*)malloc(sizeof(int) * (n + 1));

}

for(int i = 0; i <= n; ++ i)

for(int j = 0; j <= n; ++j)

tri->sym[i][j] = 0;

tri->sum = 0;

tri->count = 0;

GetTriangleSum(1,n,half,tri);

for(int i = 0; i <= n; ++i)

{

free(tri->sym[i]);

}

free(tri->sym);

free(tri);

}

最后说明这里的辅助空间可以设置为n*(n + 1) ./ 2,使用一维数组模拟二维数组。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuzhiyuxia

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值