哈密爾頓回路(旅行售貨員問題)的回溯算法


1. 回溯法的基本原理:

回溯算法也叫試探法,它是一種系統地搜索問題的解的方法。回溯算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。用回溯算法解決問題的一般步驟為:

1、定義一個解空間,它包含問題的解。

2、利用適於搜索的方法組織解空間。

3、利用深度優先法搜索解空間。

4、利用限界函數避免移動到不可能產生解的子空間。

問題的解空間通常是在搜索問題的解的過程中動態產生的,這是回溯算法的一個重要特性。

2.旅行售貨員問題的回溯算法實現

算法具體實現主要代碼如下:

// TravelSaler.cpp : 定義控制台應用程序的入口點。

//

//旅行員售貨員問題 回溯法求解

#include "stdafx.h"

#include <iostream>

#include <fstream>

#include<stdlib.h>

using namespace std;

 

ifstream fin("input.txt");

const int N = 4;//圖的頂點數

 

template<class Type>

class Traveling

{

    template<class Type>

    friend Type TSP(Type **a, int n);

private:

    void Backtrack(int i);

    int n,         // 圖G的頂點數

        *x, // 當前解

        *bestx; // 當前最優解

    Type **a, // 圖G的領接矩陣

        cc, // 當前費用

        bestc; // 當前最優值

    int NoEdge; // 無邊標記

};

 

template <class Type>

inline void Swap(Type &a, Type &b);

 

template<class Type>

Type TSP(Type **a, int n);

 

int main()

{

    cout << "圖的頂點個數 n=" << N << endl;

 

    int **a = new int*[N + 1];

    for (int i = 0; i <= N; i++)

    {

        a[i] = new int[N + 1];

    }

 

    cout << "圖的鄰接矩陣為:" << endl;

 

    for (int i = 1; i <= N; i++)

    {

        for (int j = 1; j <= N; j++)

        {

            fin >> a[i][j];

            cout << a[i][j] << " ";

        }

        cout << endl;

    }

    cout << "最短回路的長為:" << TSP(a, N) << endl;

 

    for (int i = 0; i <= N; i++)

    {

        delete[]a[i];

    }

    delete[]a;

 

    a = 0;

    system("pause");

    return 0;

    

}

 

template<class Type>

void Traveling<Type>::Backtrack(int i)

{

    if (i == n)

    {

        if (a[x[n - 1]][x[n]] != 0 && a[x[n]][1] != 0 &&

            (cc + a[x[n - 1]][x[n]] + a[x[n]][1] < bestc || bestc == 0))

        {

            for (int j = 1; j <= n; j++) bestx[j] = x[j];

            bestc = cc + a[x[n - 1]][x[n]] + a[x[n]][1];

        }

    }

    else

    {

        for (int j = i; j <= n; j++)

        {

            // 是否可進入x[j]子樹?

            if (a[x[i - 1]][x[j]] != 0 && (cc + a[x[i - 1]][x[i]] < bestc || bestc == 0))

            {

                // 搜索子樹

                Swap(x[i], x[j]);

                cc += a[x[i - 1]][x[i]]; //當前費用累加

                Backtrack(i + 1);            //排列向右擴展,排列樹向下一層擴展

                cc -= a[x[i - 1]][x[i]];

                Swap(x[i], x[j]);

            }

        }

    }

}

 

template<class Type>

Type TSP(Type **a, int n)

{

    Traveling<Type> Y;

    Y.n = n;

    Y.x = new int[n + 1];

    Y.bestx = new int[n + 1];

 

    for (int i = 1; i <= n; i++)

    {

        Y.x[i] = i;

    }

 

    Y.a = a;

    Y.cc = 0;

    Y.bestc = 0;

 

    Y.NoEdge = 0;

    Y.Backtrack(2);

 

    cout << "最短回路為:" << endl;

    for (int i = 1; i <= n; i++)

    {

        cout << Y.bestx[i] << " --> ";

    }

    cout << Y.bestx[1] << endl;

 

    delete[] Y.x;

    Y.x = 0;

    delete[] Y.bestx;

 

    Y.bestx = 0;

    return Y.bestc;

}

 

template <class Type>

inline void Swap(Type &a, Type &b)

{

    Type temp = a;

    a = b;

    b = temp;

}

其中input.txt的內容為:

0 30 6 4

30 0 5 10

6 5 0 20

4 10 20 0

編譯並運行程序。

3. 旅行售貨員問題的回溯算法的解空間樹以及搜索過程:

3)算法的時間復雜性和空間復雜性

 算法backtrack在最壞情況下可能需要更新當前最優解O((n-1)!)次,每次更新bestx需計算時間O(n),從而整個算法的計算時間復雜性為O(n!) 

程序運行結果如下:

 

開始測試時每次都要輸入圖的鄰接矩陣,非常麻煩,后面改為直接從input文件中讀取,大大簡化了調試過程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM