题目: 下面都是“-”。 下图是由14个“+”和14个“-”组成的符号三角形。2个同号下面都是“+”,2个异号下面都是“-”。
+ + - + - + +
+ - - - - +
- + + + -
- + + -
- + -
- -
+
在一般情况下,符号三角形的第一行有n个符号。符号三角形问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。
思路:我们首先要遍历第一行的所有情况(为了简化问题,我们用0代表+,1代表-,这样根据异或的规则,正好满足题意,又方便了计数)。
注意这里要有剪枝,通过观察我们发现,满足条件的所有三角形中除了初始的3个字符的三角形,其他所有满足结果要求的子三角形中,+和-的个数都是相同的,
这样我们进行剪枝,不等的直接return。另外一个是要特判初始的总数,奇数肯定是不行的。然后注意回溯的时候对sum值进行修改。
剩下的就是dfs的功底了。
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int n,half,ans,sum;
int s[100][100];
void dfs(int t,int sum)
{
if(sum>half||t*(t-1)/2-sum>half)//已经算出的子树不满足,剪枝
return ;
if(t>n)//满足要求,相等
{
ans++;
/* 输出满足条件的矩阵
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<s[i][j];
cout<<endl;
}
cout<<endl;*/
return ;
}
for(int i=0;i<2;i++)
{
s[1][t]=i;
for(int j=2;j<=t;j++)
{
s[j][t-j+1]=s[j-1][t-j+1]^s[j-1][t-j+2];//递推子树
sum+=s[j][t-j+1];
}
dfs(t+1,sum+i);
for(int j=2;j<=t;j++)//回溯时取消上一次的赋值
sum-=s[j][t-j+1];
}
}
int main()
{
//n为输入的第一行的个数
while(cin>>n)
{
ans=0,sum=0;
half=n*(n+1)/2;
memset(s,0,sizeof(s));
if(half%2!=0)//总数是奇数直接判0
{
cout<<0<<endl;
}
else
{
half/=2;//总数的一半
dfs(1,0);
cout<<"满足条件的三角形的个数是:"<<endl;
cout<<ans<<endl;
}
}
return 0;
}