您的位置:首页 > 其它

符号三角形问题;回溯算法;子集树问题;时间复杂度O(2的n次方);

2010-04-02 16:12 393 查看
#include <iostream>
using namespace std;

class Triangle
{
private:
int num;//第一行的符号数量
int **p;//存储+ -号,0表示-,1表示+
int count;//记录+号数量,根据+号数量,可以用i*(i+1)/2-count求出减号数量
int sum;//记录+与-数量相等且等于num*(num+1)/4的情况
const int half;//加号=等号=总符号数/2
public:
//构造函数
Triangle(int num):half(num*(num+1)/4)
{
this->num=num;
count=0;
sum=0;

p=new int* [num+1];
for(int i=0;i<=num;i++)
{
p[i]=new int[num+1];//开辟一个num*num的矩阵,用于在回溯过程中记录三角形符号分布
}
}
//调用回溯算法,并且先判断num*(num+1)/2是否为奇数
void triangleSolve()
{
if(num*(num+1)/2%2==0)
{
triangle(1);
display();
}
else
{
cout<<"不存在可能性"<<endl;
return;
}
}
//回溯核心算法
void triangle(int i)
{
if(i>num)
{
++sum;
return;
}

for(int j=0;j<=1;j++)
{
p[1][i]=j;
count+=j;
for(int k=2;k<=i;k++)
{
p[k][i-k+1]=p[k-1][i-k+1]^p[k-1][i-k+2];//相同则为1,不同则为0,代表题目的规则.1为+,0为-
count+=p[k][i-k+1];
}
if(count<=half&&i*(i+1)/2-count<=half)//剪枝函数,约束函数,如果当前的+,-都小于符号数一半,那么继续递归
{
triangle(i+1);
}
//恢复现场
for(int k=2;k<=i;k++)
{
count-=p[k][i-k+1];//减去新加入右侧边的+符号数量
}
count-=j;//减去i位置的+数量
}
}
void display()
{
cout<<"边长为"<<num<<"的情况下,一共有"<<sum<<"种符号三角形具有同等数量的+与-号"<<endl;
}
};

void main()
{
Triangle test(7);//设置第一行有7个符号
test.triangleSolve();//解决问题
}


 

求+,-数量相等的三角形数量,整个三角形只与第一行的符号有关。

 

所以可以逐次安排第一行的每一个符号,由于每次安排好一个符号,那么就会在原确定的三角形最右侧加一条三角形边。 所以,利用回溯法,逐次对第一行每一个位置的符号做出选择,并且扩充新的三角形边。 为了实现回溯算法的优化,必须有剪枝函数,所以这里用+,-都小于总符号数的一半作为约束,只要能够递归到第n+1个字符,说明1到n个字符的安排都满足+<=half,-<=half,所以就是+与-数量相等,sum++。  为了在回溯过程中能够及时的计算出三角形的最新状况,所以设置了二维数组用于存储三角形,根据图形的关系可以求出三角形的右侧边加入到二维数组中。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐