符号三角形的回溯算法(王晓东算法分析例题)

来源:互联网 发布:钓鱼软件app 编辑:程序博客网 时间:2024/06/02 01:06

题目: 下面都是“-”。 下图是由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;}


1 0