本题描述的是巡回收货商
问题:给出一个城市列表以及每对城市之间的距离,求每个城市均被访问之后再返回原城市的最短路径。显然,整个路径会构成一个环。本题中,你需要从给定的环中找到最接近旅行商问题的解的环。
输入第一行包含 2 个正整数 N 和 M,分别表示无向图的顶点个数和边的个数。接下来 M 行,每行通过给出两个结点的编号以及这两个结点之间的距离,表示这两个结点之间存在一条边。其中顶点从 1 到 N 编号。接下来一行给出一个正整数 K,表示查询的数量。然后是 K 行查询,每行以$n\ V_1\ V_2\cdots V_n$的格式给出一个路径的顶点序列。
对于每个路径,首先以Path X: TotalDist (Description)
的格式打印一行,其中 X 是该路径的编号(从 1 开始),TotalDist 是路径的总长度(如果不存在此距离,则输出 NA),并且 Description 为以下文字描述之一:
- 如果给定的路径是包含所有顶点的简单环,则为
TS simple cycle
; - 如果给定的路径是包含所有顶点的环,但不是简单环,则为
TS cycle
; - 如果给定的路径不是包含所有顶点的环,则为
Not a TS cycle
;
最后一行以Shortest Dist(X) = TotalDist
格式打印,其中 X 是最接近旅行商问题解决方案的路径编号,TotalDist 是其总长度。题目保证这个解是唯一的。
针对一个路径,判断的过程可以是这样的:
- 如果路径中某两个相邻结点之间没有边,或首尾结点不相同(即不能构成一个环),或没有包含图中所有顶点,输出
Not a TS cycle
; - 否则,如果路径中,首尾结点出现出现两次,其它结点出现 1 次,则为
TS simple cycle
; - 否则为
TS cycle
。
还要注意,在统计最短距离时,属于Not a TS cycle
的路径不要统计在内。
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
gg ni, mi, ki;
cin >> ni >> mi;
vector<vector<gg>> graph(ni + 1, vector<gg>(ni + 1));
while (mi--) {
gg ai, bi, ci;
cin >> ai >> bi >> ci;
graph[ai][bi] = graph[bi][ai] = ci;
}
cin >> mi;
gg num = -1, dis = INT_MAX;
for (gg ii = 1; ii <= mi; ++ii) {
cout << "Path " << ii << ": ";
cin >> ki;
vector<gg> v(ki);
for (gg& i : v) {
cin >> i;
}
gg curdis = 0;
unordered_set<gg> us{v[0]};
for (gg i = 1; i < v.size(); ++i) { //判断每两个顶点之间是否有边
if (graph[v[i]][v[i - 1]] == 0) { //两个顶点之间没有边
cout << "NA (Not a TS cycle)\n";
goto loop;
}
us.insert(v[i]);
curdis += graph[v[i - 1]][v[i]];
}
if (v.front() != v.back() or us.size() != ni) { //不是TS环
cout << curdis << " (Not a TS cycle)\n";
} else {
if (us.size() != v.size() - 1) { //不是TS简单环
cout << curdis << " (TS cycle)\n";
} else {
cout << curdis << " (TS simple cycle)\n";
}
if (curdis < dis) {
dis = curdis;
num = ii;
}
}
loop:;
}
cout << "Shortest Dist(" << num << ") = " << dis;
return 0;
}