1. 程式人生 > 其它 >回溯演算法 --- 例題3.符號三角形問題

回溯演算法 --- 例題3.符號三角形問題

一.問題描述

下圖是由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;
}

執行結果如下:

參考畢方明老師《演算法設計與分析》課件.

歡迎大家訪問個人部落格網站---喬治的程式設計小屋,和我一起加油吧!