c++ 如何使用DP和位掩码解决旅行商问题中的路径跟踪

zf2sa74q  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(145)

我写了代码来解决TSP(旅行推销员问题)使用DP,但我不知道如何跟踪路径,给出解决方案。
这是代码:

  1. static int tsp(std::vector<std::vector<int>> const& dist, size_t current, uint64_t mask, std::vector<std::vector<int>>& dp) {
  2. if (mask == ((size_t)1 << dist.size()) - 1)
  3. return dist[current][0];
  4. if (dp[mask][current] != -1)
  5. return dp[mask][current];
  6. int result = INT_MAX;
  7. for (uint64_t i = 0; i < dist.size(); ++i) {
  8. uint64_t val = (uint64_t)1 << i;
  9. if (mask & val)
  10. continue;
  11. int sub = dist[current][i] + tsp(dist, i, mask | val, dp);
  12. result = std::min(result, sub);
  13. }
  14. dp[mask][current] = result;
  15. return result;
  16. }
  17. int main()
  18. {
  19. std::vector<std::vector<int>> dist{
  20. {0, 10, 41, 31},
  21. {10, 0, 30, 19},
  22. {41, 30, 0, 20},
  23. {31, 19, 20, 0}
  24. };
  25. std::vector<std::vector<int>> dp(1 << dist.size(), std::vector<int>(dist.size(), -1));
  26. std::cout << (tsp(dist, 0, 1, dp) == 90);
  27. }

字符串
我试图通过std::vector<int>& path作为tsp参数和工作时,我有更好的结果比当前的i节点path[i] = current,但它不工作.我认为它不工作,因为最好的结果在某个时刻不是最好的整个解决方案(例如,整个解决方案可能会访问节点在不同的顺序,他们不能被重新访问).
你可能想知道这段代码是如何检查节点是否被访问的。我通过位掩码来完成,过程可能看起来像这样(对于4个节点A,B,C,D):

main



预期路径为:0-1-3-2-0(成本等于90)
那么,在TSP问题中,如何跟踪给出最优解的路径呢?

ppcbkaq5

ppcbkaq51#

您可以添加一个参数(我们称之为link),用于收集给定掩码和节点的最佳邻居。因此它将具有与dp相同的类型。
然后在tsp运行之后,您可以使用此数据结构来重建路径。
下面是你的代码和必要的补充:

  1. static int tsp(std::vector<std::vector<int>> const& dist,
  2. size_t current, uint64_t mask,
  3. std::vector<std::vector<int>>& dp,
  4. std::vector<std::vector<int>>& link) { // new parameter
  5. if (mask == ((size_t)1 << dist.size()) - 1)
  6. return dist[current][0];
  7. if (dp[mask][current] != -1)
  8. return dp[mask][current];
  9. int result = INT_MAX;
  10. for (uint64_t i = 0; i < dist.size(); ++i) {
  11. uint64_t val = (uint64_t)1 << i;
  12. if (mask & val)
  13. continue;
  14. // Pass extra argument in recursive call
  15. int sub = dist[current][i] + tsp(dist, i, mask | val, dp, link);
  16. if (sub < result) {
  17. result = sub;
  18. link[mask][current] = i; // Register which neighbor was best
  19. }
  20. }
  21. dp[mask][current] = result;
  22. return result;
  23. }
  24. // Function to translate `link` into a path, assuming 0 is starting node
  25. static std::vector<int> getpath(std::vector<std::vector<int>>& link) {
  26. size_t current = 0;
  27. uint64_t mask = 0;
  28. std::vector<int> path;
  29. for (int i = 0; i < link[0].size(); i++) {
  30. path.push_back(current);
  31. mask |= 1 << current;
  32. current = link[mask][current];
  33. }
  34. return path;
  35. }
  36. int main() {
  37. std::vector<std::vector<int>> dist{
  38. {0, 10, 41, 31},
  39. {10, 0, 30, 19},
  40. {41, 30, 0, 20},
  41. {31, 19, 20, 0}
  42. };
  43. std::vector<std::vector<int>> dp(1 << dist.size(), std::vector<int>(dist.size(), -1));
  44. std::vector<std::vector<int>> link(1 << dist.size(), std::vector<int>(dist.size(), 0));
  45. int res = tsp(dist, 0, 1, dp, link);
  46. std::vector<int> path = getpath(link);
  47. std::cout << "result " << res << "\n";
  48. for (auto i : path)
  49. std::cout << i << " ";
  50. std::cout << "\n";
  51. }

字符串
请注意,您的代码假设0是起始节点(请参阅基本情况),因此我在getpath中使用了相同的假设。

展开查看全部

相关问题