符号三角形问题
2017-07-20 13:09
225 查看
/* Name: 符号三角形问题 Copyright: free Author: 巧若拙 Date: 20-07-17 10:42 Description: 问题描述: 如下图是由14个“+”和14个“-”组成的符号三角形, 2个同号下面都是“+”,2个异号下面都是“-”。 - + + - + + + - + - - + + - - + - + + - - - - + + - + - 在一般情况下,符号三角形的第一行有n个符号, 符号三角形问题要求对于给定的n, 计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。 解题思路: 比较直接的想法是先回溯生成第一行符号的所有可能情况,然后按照规律生成符号三角形, 当某种符号超过总数一半时无解,直接返回。 因为每行符号都只由上一行符号决定,故可以用一维数组代替二维数组 */ #include<iostream> #include<cmath> using namespace std; const int N = 20; //符号的最大个数 char A ;//记录符号三角形矩阵的第一行 int sum = 0;//保存可以放置的方案数 int n, half; void Backtrace(int t); //递归回溯 void Solve(); int main() { n = 7; half = n*(n+1)/2; if (half%2 == 1) { cout << "无解" << endl; return 0; } half /= 2; Backtrace(0); cout << sum << endl; // system("pause"); return 0; } void Backtrace(int t) //递归生成第1行的n个符号 { if (t == n)//第一行符号生成完毕,构造三角形并判断是否有解 Solve(); else //枚举第t个符号的两种取值,并递归生成下一个符号 { A[t] = '+'; Backtrace(t+1); A[t] = '-'; Backtrace(t+1); } } void Solve() { char B ;//记录符号三角形矩阵的当前行 int s1 = 0, s2 = 0;//分别记录+和-的数量 for (int i=0; i<n; i++)//复制并累计第0行符号+和-的数量 { B[i] = A[i]; if (B[i] == '+') s1++; else s2++; } for (int i=1; i<n; i++)//第i行符号 { for (int j=0; j<n-i; j++)//生成第i行符号,共n-i个 { B[j] = (B[j]==B[j+1]) ? '+' : '-'; if (B[j] == '+') s1++; else s2++; if (s1 > half || s2 > half) //+或-超过半数即返回(无解) return; } } if (s1 == s2) sum++; }
/* Name: 符号三角形问题 Copyright: free Author: 巧若拙 Date: 20-07-17 10:42 Description: 问题描述: 如下图是由14个“+”和14个“-”组成的符号三角形, 2个同号下面都是“+”,2个异号下面都是“-”。 - + + - + + + - + - - + + - - + - + + - - - - + + - + - 在一般情况下,符号三角形的第一行有n个符号, 符号三角形问题要求对于给定的n, 计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。 解题思路: 1、不断改变第一行每个符号,搜索符合条件的解,可以使用递归回溯 为了便于运算,设+ 为0,- 为1,这样可以使用异或运算符表示符号三角形的关系 ++为+即0^0=0, --为+即1^1=0, +-为-即0^1=1, -+为-即1^0=1; 2、因为两种符号个数相同,可以对题解树剪枝, 当所有符号总数为奇数时无解,当某种符号超过总数一半时无解 本算法采用了两个技巧:一是用0和1代替+和-,这样可以用异或运算生成新的符号,同时可以快速记录符号1的数量; 二是回溯时每次只增加第一行的一个符号,然后利用异或运算规律生成对应的三角形(每次每行只增加一个符号,刚好形成一条斜线), 这样无需把全部三角形都生成后再判断符号个数,大大提高了效率。 */ #include<iostream> #include<cmath> using namespace std; const int N = 20; //符号的最大个数 int map ;//记录符号三角形矩阵 int sum = 0;//保存可以放置的方案数 int n, half; int s1;//记录1(即-)的数量,0的数量即总数减去1的数量 void Backtrace(int t); //递归回溯 int main() { n = 7; half = n*(n+1)/2; if (half%2 == 1) { cout << "无解" << endl; return 0; } half /= 2; Backtrace(0); cout << sum << endl; // system("pause"); return 0; } void Backtrace(int t) //递归回溯,t表示第t行 { if (s1 > half || t*(t+1)/2-s1 > half) //1或0超过半数即返回(无解) return; if (t == n)//符号三角形矩阵构造完毕,增加一个解 { sum++; cout << sum << endl; for (int r=0; r<n; r++) { for (int k=0; k<n-r; k++) { cout << map[r][k]; } cout << endl; } cout << endl; return; } for (int i=0; i<2; i++)//符号只有0和1两种选择 { map[0][t] = i; //生成第0行的第t个符号(下标从0开始) s1 += i; //使用了一个技巧:记录符号1的数量,若为符号0,则不会累积 //根据第0行的符号,按异或运算规律从第1行开始生成新的符号,第0行每次增加一个符号,则按照从右上到左下斜线的顺序在每行都生成一个新的符号 for (int j=1; j<=t; j++) { map[j][t-j] = map[j-1][t-j]^map[j-1][t-j+1]; //按斜线顺序生成一个新符号 s1 += map[j][t-j]; } Backtrace(t+1); //还原 for (int j=1; j<=t; j++) { s1 -= map[j][t-j]; } s1 -= i; } }
相关文章推荐
- 第5章 回溯法,符号三角形问题
- 符号三角形问题 回溯法
- 实验四 回溯算法和分支限界法 符号三角形问题
- 符号三角形问题
- 符号三角形问题(回溯)
- 【a502】符号三角形问题
- 回溯法求解符号三角形问题
- 0028算法笔记——【回溯法】批作业调度问题和符号三角形问题
- 算法 符号三角形问题
- 符号三角形问题-回溯法
- CodeDom系列二---程序基本结构--符号三角形问题
- 符号三角形问题C++代码
- 符号三角形问题(dfs)
- 算法设计_回溯法_符号三角形问题
- CodeDom系列二---程序基本结构--符号三角形问题
- 算法java实现--回溯法--符号三角形问题
- 符号三角形问题
- 符号三角形问题
- 符号三角形问题
- 符号三角形问题