一。问题介绍
旅行商问题,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求的路径路程为所有路径之中的最小值。
二。解决方法(理论)
TSP是一道经典的NP-完全问题。在规模比较小的时候,可以用动态规划求解。
有n个城市,两两之间均有道路直接相连,给出每个城市i和j之间的道路长度dist(i, j)。求一条经过每个城市一次且仅一次,最后回到起点的路线,使得经过的道路总长度最短。n<=16,城市编号为0~n-1。
因为路线是一个环,可以规定任意点为起点和终点,不妨设城市0为起点和终点。设d(s,i)表示“当前在i城市,已访问城市集合为s”的最短长度,则d(s, i)=min{d(s - i, j) + dist(j, i) | i∈S}.
初始时d({0},0)=0,最终答案为min{d({0,1,2,,,,n-1}, i) + dist(i, 0) | i≠0}
时间复杂度为O()。
根据该思路可以写下如下代码:
memset(dp, 0x3f, sizeof(dp));
dp[1][0] = 0;
for (int s = 0; s < (1<<n); s++) { //枚举集合状态s
for (int i = 0; i < n; i++) { //枚举当前的点i
if (s & (1<<i)) {
for (int j = 0; j < n; j++) { //枚举之前的点j
if (j != i && (s & (1<<j)) {
dp[s][i] = min(dp[s][i], dp[s ^ (1<<i)][j] + dist[j][i]); //根据之前的点j,更新当前的点i。
}
}
}
}
}
int ans = INF:
for (int i = 1; i < n; i++) { //注意这里的i是从1开始的,因为访问城市的时候我们规定从0号城市访问,要走一个回路需要走n步,第n-1步必须是非0号城