分支限界解决TSP算法

分支限界解决TSP算法

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <omp.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <limits>
#include <queue>
#include <array>
#include <algorithm>
#include <numeric>
#include <set>

#define INVALID_VALUE 0
int times = 0;
int N;
int up_bound = INT_MAX;
int low_bound = INT_MAX;
int** adj;
std::vector<std::pair<int, int>> shortRoadVec;
std::vector<int> lowBoundVec;
std::vector<int> greedyPath;
std::set<int> remaind;

const int INF = std::numeric_limits<int>::max();

struct node
{
  int row;
  int cost;
  bool visit;
  std::vector<int> path;  // 记录节点的路径
  node()
  {
    row = 0;
    cost = 0;
    visit = false;
    path.clear();
  }
  struct Compare
  {
    bool operator()(const node& n1, const node& n2)
    {
      return n1.cost > n2.cost;
    }
  };
};

class selectedArray
{
  std::vector<int> array;

public:
  selectedArray()
  {
    array.clear();
  }
  void add(int in)
  {
    array.push_back(in);
  }

  void remove(int in)
  {
    auto it = std::find(array.begin(), array.end(), in);
    if (it != array.end())
    {
      array.erase(it);
    }
  }

  bool isHave(int in)
  {
    auto it = std::find(array.begin(), array.end(), in);
    if (it != array.end())
    {
      return true;
    }
    return false;
  }

  int size()
  {
    return array.size();
  }
  int back()
  {
    return array.back();
  }
};

class BABnode
{
public:
  int num;
  int level;
  std::vector<int> path;
  int length;
  int low_b;
  int finish_dis = 0;
  int remaind_dis = 0;
  std::set<int> finish_city;
  std::set<int> remaind_city;

  BABnode()
  {
    num = 0;
    level = 0;
    path.clear();
    length = 0;
    low_b = 0;
    finish_dis = 0;
    remaind_dis = 0;
    finish_city.clear();
    remaind_city.clear();
  }

  BABnode(int num, int level, std::vector<int> path, int length, int low_b, std::set<int> finish_city,
          std::set<int> remaind_city)
    : num(num)
    , level(level)
    , path(path)
    , length(length)
    , low_b(low_b)
    , finish_city(finish_city)
    , remaind_city(remaind_city)
  {
    ;
  }

  bool operator<(const BABnode& other) const
  {
    return low_b > other.low_b;  // 以小到大的顺序进行比较
  }
};

// 旅行商问题的求上界函数
int getUpperBound(std::vector<std::priority_queue<node, std::vector<node>, node::Compare>> graph, int first)
{
  // 待选行
  selectedArray selected_array;
  for (int i = 0; i < graph.size(); i++)
  {
    selected_array.add(i);
  }

  // 取第一行最小代价
  node min_node;
  int upperBound = 0;
  int next = first;

  // std::cout << " 下一行取 " << next << std::endl;
  for (int i = 0; i < graph.size(); i++)
  {
    while (1)
    {
      min_node = graph.at(next).top();
      if (selected_array.isHave(min_node.row) && min_node.cost > 0)
      {
        upperBound += min_node.cost;
        greedyPath.push_back(next);
        selected_array.remove(next);
        next = min_node.row;
        break;
      }
      else if (selected_array.size() <= 1)
      {
        std::cout << " 搜完!!" << std::endl;
        break;
      }
      else if (selected_array.size() > 1 && graph.at(next).size() <= 0)
      {
        std::cout << " 路径不闭环" << std::endl;
        return 0;
      }
      else
      {
        graph.at(next).pop();
      }
    }
  }
  // std::cout << " 最后一个 = " << selected_array.back() << std::endl;

  upperBound += adj[selected_array.back()][first];
  return upperBound;
}

void getLowBound(std::vector<std::priority_queue<node, std::vector<node>, node::Compare>> map)
{
  low_bound = 0;
  for (auto A : map)
  {
    while (1)
    {
      if (A.size() < 2)
      {
        break;
      }
      else if (A.top().cost != INVALID_VALUE)
      {
        std::pair<int, int> short_path;
        short_path.first = A.top().cost;
        A.pop();
        short_path.second = A.top().cost;
        shortRoadVec.push_back(short_path);
        int tmp = (short_path.first + short_path.second);
        low_bound += tmp;
        lowBoundVec.push_back(tmp);
        break;
      }
      else
      {
        A.pop();
      }
    }
  }
  low_bound = low_bound & 1 ? low_bound / 2 + 1 : low_bound / 2;
}
int getNodeLowBound(BABnode in, int next, std::vector<std::pair<int, int>> shortRoadVec)
{
  int last = in.path.back();
  int tmp = adj[last][next];
  int result = in.low_b * 2;
  if (in.path.size() == 1)  // 改变四个变量 v0firstMin , v0secMin  ,v1firstmin , v1secMin变成v0Min , v01  ,v1min , v10
  {
    // 求v0firstMin shortRoadVec.at(last).first
    // 求v0secMin shortRoadVec.at(last).second
    // 求v1firstmin shortRoadVec.at(next).first
    // 求v1secMin shortRoadVec.at(next).second
    // 求v01

    int V01 = adj[last][next];
    // 求v0Min
    int V0min = 0;
    if (V01 != shortRoadVec.at(last).first)
    {
      V0min = shortRoadVec.at(last).first;
    }
    else
    {
      V0min = shortRoadVec.at(last).second;
    }
    // 求v10
    int V10 = adj[next][last];
    // 求v1Min
    int V1min = 0;
    if (V10 != shortRoadVec.at(next).first)
    {
      V1min = shortRoadVec.at(next).first;
    }
    else
    {
      V1min = shortRoadVec.at(next).second;
    }
    result = result - shortRoadVec.at(last).first - shortRoadVec.at(last).second - shortRoadVec.at(next).first -
             shortRoadVec.at(next).second;
    result = result + V01 + V0min + V10 + V1min;
  }
  else  // 改变三个变量 v1Min   ,v2firstmin , v2secMin变成v12 , v21  ,v2min
  {     // 求v1Min
    int V1min = 0;
    int last_last = in.path.at(in.path.size() - 2);
    if (adj[last_last][last] != shortRoadVec.at(last).first)
    {
      V1min = shortRoadVec.at(last).first;
    }
    else
    {
      V1min = shortRoadVec.at(last).second;
    }
    // 求v2firstmin shortRoadVec.at(next).first;
    // 求 v2secMin shortRoadVec.at(next).second;
    // 求 v12
    int V12 = adj[last][next];
    // 求 v21
    int V21 = adj[next][last];
    // 求 v2min
    int V2min = 0;
    if (V21 != shortRoadVec.at(next).first)
    {
      V2min = shortRoadVec.at(next).first;
    }
    else
    {
      V2min = shortRoadVec.at(next).second;
    }
    result = result - V1min - shortRoadVec.at(next).first - shortRoadVec.at(next).second;
    result = result + V12 + V21 + V2min;
  }
  if (result / 2 < in.low_b)
  {
    std::cout << result / 2 << " 出现了异常  " << in.low_b << " \n  ";
  }
  return result / 2;
}

BABnode TSPBranchAndBound(int** graph, BABnode startNode, int n)
{
  std::priority_queue<BABnode> activeNodes;
  activeNodes.push(startNode);
  BABnode CurrentNode, result;

  while (!activeNodes.empty())
  {
    CurrentNode = activeNodes.top();
    activeNodes.pop();
    // 找到了全部路径,更新上界
    if (CurrentNode.level == n - 1)
    {
      int length = CurrentNode.length + graph[CurrentNode.path.back()][CurrentNode.path.front()];
      if (length <= up_bound)
      {
        up_bound = length;
        result = CurrentNode;
        result.length = length;
        // return result;
      }
    }
    else
    {
      for (auto i : CurrentNode.remaind_city)
      {
        int node_low_bound = getNodeLowBound(CurrentNode, i, shortRoadVec);
        BABnode tmp = CurrentNode;
        if (node_low_bound <= up_bound)
        {
          tmp.low_b = node_low_bound;
          tmp.length += graph[CurrentNode.path.back()][i];
          tmp.path.push_back(i);
          tmp.remaind_city.erase(i);
          tmp.finish_city.insert(i);
          tmp.level++;
          activeNodes.push(tmp);
        }
      }
    }
  }
  return result;
}

int main(int argv, char* argc[])
{
  std::vector<std::priority_queue<node, std::vector<node>, node::Compare>> graph_vec;
  int n;
  std::cin >> n;

  for (int i = 1; i < n; i++)
  {
    remaind.insert(i);
  }

  int* data = (int*)malloc(n * n * sizeof(int));
  adj = (int**)malloc(n * sizeof(int*));
  for (int i = 0; i < n; i++)
    adj[i] = &(data[i * n]);

  N = n;
  for (int i = 0; i < n; i++)
  {
    std::priority_queue<node, std::vector<node>, node::Compare> tmp_vec;
    struct node tmp_node;
    for (int j = 0; j < n; j++)
    {
      scanf("%d", &adj[i][j]);
      tmp_node.cost = adj[i][j];
      tmp_node.row = j;
      tmp_node.visit = false;
      if (tmp_node.cost != INVALID_VALUE)
        tmp_vec.push(tmp_node);
    }
    graph_vec.push_back(tmp_vec);
  }

//   std::vector<int> input;
//   int tmp = 0;
//   for (int i = 0; i < n; i++)
//   {
//     scanf("%d", &tmp);
//     input.push_back(tmp);
//   }
//   int sum = 0;
//   for (int i = 0; i < n - 1; i++)
//   {
//     sum += adj[input.at(i)][input.at(i + 1)];
//   }
//   sum += adj[input.at(n - 1)][input.at(0)];
//   std::cout << " 计算得的总代价 = " << sum << std::endl;

  for (int i = 0; i < graph_vec.size(); i++)
  {
    up_bound = std::min(up_bound, getUpperBound(graph_vec, i));
    std::cout << "上界 = " << up_bound << std::endl;
  }

  getLowBound(graph_vec);
  std::cout << "下界 = " << low_bound << std::endl;

  BABnode start_node(0, 0, { 0 }, 0, low_bound, std::set<int>(), remaind);
  BABnode result = TSPBranchAndBound(adj, start_node, n);

  printf("Minimum cost : %d\n", result.length);
  printf("Path Taken : ");
  for (int i = 0; i < N; i++)
    printf("%d ", result.path[i]);

  free(data);
  free(adj);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
支限界法类又称为剪枝限界法或分支定界法,它类似于回溯法,也是一种在问题的空间树T上搜索问题算法。它与回溯法有两点不同:①回溯法只通过约束条件剪去非可行,而分支限界法不仅通过约束条件,而且通过目标函数的限界来减少无效搜索,也就是剪掉了某些不包含最优的可行。②在空间树上的搜索方式也不相同。回溯法以深度优先的方式搜索空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索空间树。分支限界法的搜索策略是:在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一个扩展结点。为了有效地选择下一扩展结点,以加速搜索的进程, 在每一活结点处,计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着空间树上有最优分支推进,以便尽快地找出一个最优。 从活结点表中选择下一扩展结点的不同方式导致不同的分支限界法。最常见的有以下两种方式: ①队列式(FIFO)分支限界法:队列式分支限界法将活结点表组织成一个队列,并按队列的先进先出原则选取下一个结点为当前扩展结点。 ②优先队列式分支限界法:优先队列式分支限界法将活结点表按照某个估值函数C(x)的值组织成一个优先队列,并按优先队列中规定的结点优先级选取优先级最高的下一个结点成为当前扩展结点。 影响分支限界法搜索效率的有两个主要因素:一是优先队列Q的优先级由C(x)确定,它能否保证在尽可能早的情况下找到最优,如果一开始找到的就是最优,那么搜索的空间就能降低到最小。二是限界函数u(x),它越严格就越可能多地剪去分支,从而减少搜索空间。 在用分支限界解决TSP问题时,有不少很好的限界函数和估值函数已经构造出来出了(限于篇幅,这里不做详细介绍), 使得分支限界法在大多数情况下的搜索效率大大高于回溯法。但是,在最坏情况下,该算法的时间复杂度仍然是O(n!),而且有可能所有的(n-1)!个结点都要存储在队列中。 近似算法是指不能肯定找到最优算法,但通常找到的也是比较好的,或称近似最优。[20]一般而言,近似算法的时间复杂度较低,通常都是多项式时间内的。由于近似算法的时间效率高,所以在实际应用中,主要是使用近似算法,这一类算法也一直是研究的主要对象。传统的近似算法以采用贪心策略和局部搜索为主,而几十年来,随着以遗传算法为代表的新型启发式搜索算法的逐步完善,在解决TSP问题上获得了巨大的成功。遗传算法、模拟退火算法、蚁群算法等已经成为公认的好算法。在本节中,将介绍传统的近似算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangming12345678

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值