用分枝-限界法解决旅行商问题(C++实现)

1,720 阅读2分钟
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <climits>

using namespace std;
// 问题规模
const unsigned N = 5;

class Node {
public:
    Node(unsigned vertex) {
        path.push_back(vertex);
    }

    Node(const Node &src, unsigned vertex, unsigned newCost) {
        path = src.getPath();
        path.push_back(vertex);
        cost = newCost;
    }

    friend bool operator<(const Node &a, const Node &b) {
        return a.getCost() > b.getCost();
    }

    vector<unsigned> getPath() const {
        return path;
    }

    unsigned getCost() const {
        return cost;
    }

    vector<unsigned> getAvailableNextVertexes() const {
        vector<unsigned> vertexes;
        for (unsigned i = 0; i < N; ++i) {
            if (find(path.begin(), path.end(), i) == path.end()) {
                vertexes.push_back(i);
            }
        }
        return vertexes;
    }

    unsigned getLastVertex() const {
        return path.back();
    }

private:
    unsigned cost = 0;
    vector<unsigned> path{};

};


void solute(vector<vector<unsigned>> &matrix) {
    // 优先队列
    priority_queue<Node> state;
    // 当前最优值cost
    unsigned currentOptimizedCost = INT_MAX;
    // 当前最优cost对应的路径
    vector<Node> currentOptimizedPaths{};
    // 将第一个点放入优先队列中
    state.push(Node(0));
    while (!state.empty()) {
        // 获取优先队列中优先级最高的节点
        Node currentNode = state.top();
        state.pop();
        // 获取接下来可用的顶点
        auto availableVertexes = currentNode.getAvailableNextVertexes();
        // if 可用顶点只有一个(搜索马上结束)
        if (availableVertexes.size() == 1) {
            // 获取唯一可用的顶点
            unsigned vertex = availableVertexes[0];
            // 获取路径上最后最后一个顶点
            unsigned lastVertex = currentNode.getLastVertex();
            // 顶点连接到路径上后的路径长度
            unsigned tempCost = currentNode.getCost() + matrix[lastVertex][vertex];
            // 当前搜索节点
            Node tempNode(currentNode, vertex, tempCost);
            // [剪枝]如果顶点连接到路径上后的路径长度小于当前最优路径的长度
            if (tempCost < currentOptimizedCost) {
                // 加上返回起始点后完整的路径长度
                unsigned tempCompleteCost = tempCost + matrix[vertex][0];
                // 加上返回起始点后完整的路径搜索节点
                Node currentCompleteNode(tempNode, 0, tempCompleteCost);
                // 如果完整的路径长度小于当前最优cost, 就更新当前最优cost和最优路径集合
                // 如果完整的路径长度等于当前最优cost, 就将此路径加入当前最优路径集合
                // 如果完整的路径长度大于当前最优cost, 丢弃
                if (tempCompleteCost < currentOptimizedCost) {
                    currentOptimizedCost = tempCompleteCost;
                    currentOptimizedPaths = {currentCompleteNode};
                } else if (tempCompleteCost == currentOptimizedCost) {
                    currentOptimizedPaths.push_back(currentCompleteNode);
                }
            }
        } else {
            // 遍历接下来可用的顶点
            for (unsigned vertex : availableVertexes) {
                // 获取路径上最后最后一个顶点
                unsigned lastVertex = currentNode.getLastVertex();
                // 顶点连接到路径上后的路径长度
                unsigned tempCost = currentNode.getCost() + matrix[lastVertex][vertex];
                // [剪枝]如果顶点连接到路径上后的路径长度大于当前最优路径的长度, 丢弃
                if (tempCost > currentOptimizedCost) {
                    continue;
                }
                Node tempNode(currentNode, vertex, tempCost);
                state.push(tempNode);
            }
        }
    }
    cout << "最优值: " << currentOptimizedCost << endl;
    for (const Node &node : currentOptimizedPaths) {
        const vector<unsigned> &path = node.getPath();
        cout << path[0] + 1;
        for (int i = 1; i < path.size(); i++) {
            cout << "--" << path[i] + 1;
        }
        cout << endl;
    }
}


int main() {
    // 问题的邻接矩阵
    vector<vector<unsigned>> matrix{
            {0,  20, 30, 10, 11},
            {20, 0,  16, 4,  2},
            {30, 16, 0,  6,  7},
            {10, 4,  6,  0,  12},
            {11, 2,  7,  12, 0},
    };
    solute(matrix);
}