回溯演算法 --- 例題3.符號三角形問題
阿新 • • 發佈:2021-12-21
一.問題描述
下圖是由14個“+”和14個“-”組成的符號三角形。2個同號下面都是“+”,2個異號下面都是“-”。在一般情況下,符號三角形的第一行有n個符號.目標是:符號三角形問題要求對於給定的n,計算有多少個不同的符號三角形,使其所含的“+”和“-”的個數相同。
改為此:
二.解題思路
解向量用n元組x[1:n]表示符號三角形的第一行,每個元素均可取0, 1兩個值
約束函式:
- 當前符號三角形所包含的“+”個數與“-”個數均不超過 n*(n+1)/4
一個例子:第1行是4個字元的符號三角形的子集樹
具體程式碼如下:
// 符號三角形回溯演算法 #include<bits/stdc++.h> using namespace std; class Triangle { friend int Compute(int); private: void Backtrack(int t); //用類Triangle的資料成員記錄解空間中結點資訊,以減少傳給Backtrack函式的引數. int n, //第一行的符號個數 half, //n*(n+1)/4. count, //當前'+'個數 **p; //符號三角形矩陣 long sum; //已找到的符號三角形數 }; void Triangle::Backtrack(int t) { if((count>half) || t*(t-1)/2-count > half) //表示'+'號沒超過一半,'-'號也沒超過一半! return; if(t>n) sum++; //能到達葉節點,說明+,-各一半,可行解加一 else { for(int i=0; i<2; i++) //每個元素可以取兩個值(每個分支所做的事情是一樣的,所以直接用一個迴圈,不用分為左右) { p[1][t] = i; count += i; for(int j=2; j<=t; j++) //每次只計算了對角線 { p[j][t-j+1] = p[j-1][t-j+1] ^ p[j-1][t-j+2]; //只要第一行確定了,得到的符號三角形一定是唯一的! count += p[j][t-j+1]; } Backtrack(t+1); for(int j=2; j<=t; j++) //回溯,反操作 count -= p[j][t-j+1]; count -= i; } } } int Compute(int n) { Triangle X; X.n = n; X.count = 0; X.sum = 0; X.half = n*(n+1)/2; if(X.half%2 == 1) return 0; //如果給出的n使得符號三角形的符號總個數為奇數,直接return 0 X.half /= 2; int **p = new int*[n+1]; for(int i=0; i<=n; i++) p[i] = new int[n+1]; for(int i=0; i<=n; i++) { for(int j=0; j<=n; j++) p[i][j] = 0; } X.p = p; X.Backtrack(1); return X.sum; } int main() { cout<<"請輸入第一行符號的個數n: "; int n; while(cin>>n && n!=0) { cout<<"方案數: "<<Compute(n)<<endl; cout<<"請輸入第一行符號的個數n: "; } system("pause"); return 0; }
執行結果如下:
參考畢方明老師《演算法設計與分析》課件.
歡迎大家訪問個人部落格網站---喬治的程式設計小屋,和我一起加油吧!