题目描述
1150 Travelling Salesman Problem (25分)
知识点
图
实现
码前思考
我的思路是:
- 判断是否为连通路径;
- 判断起点和终点是否相等;
- 判断是否覆盖所有结点;
- 判断是否是简单环。
代码实现
#include "bits/stdc++.h"
using namespace std;
const int maxn = 250;
//采用邻接矩阵来记录
int G[maxn][maxn];
int n;
int m;
unordered_map<int,int> cnt;
//假设这么大的路径
int path[maxn];
int k;
int main(){
scanf("%d %d",&n,&m);
fill(G[0],G[0]+maxn*maxn,-1);
for(int i=0;i<m;i++){
int u;
int v;
int d;
scanf("%d %d %d",&u,&v,&d);
G[u][v] = d;
G[v][u] = d;
}
scanf("%d",&k);
int opt = INT_MAX;
int optnum = -1;
for(int i=0;i<k;i++){
int num;
scanf("%d",&num);
cnt.clear();
//距离
int dis=0;
for(int j=0;j<num;j++){
scanf("%d",&path[j]);
}
bool isC = true;
//判断首尾
int start = path[0];
int end = path[num-1];
bool isSE = true;
if(start != end){
isSE = false;
}
bool isSimple = true;
int u =start;
cnt[u]++;
for(int j=1;j<num;j++){
int v = path[j];
if(G[u][v] == -1){
isC = false;
break;
}else{
dis+=G[u][v];
cnt[v]++;
if(cnt[v] > 1 && v!=start){
isSimple = false;
}
u = v;
}
}
printf("Path %d: ",i+1);
if(isC == false){
printf("NA (Not a TS cycle)\n");
}else{
//如果连同看首尾
if(isSE){
//首尾相连
//看是否所有点的点都在里面
if(cnt.size() != n){
printf("%d (Not a TS cycle)\n",dis);
}else{
//已经是环了
if(isSimple){
printf("%d (TS simple cycle)\n",dis);
}else{
printf("%d (TS cycle)\n",dis);
}
if(dis < opt){
opt=dis;
optnum=i+1;
}
}
}else{
printf("%d (Not a TS cycle)\n",dis);
}
}
}
printf("Shortest Dist(%d) = %d",optnum,opt);
return 0;
}
码后反思
- 柳神的写法非常见解:
#include <iostream> #include <vector> #include <set> using namespace std; int e[300][300], n, m, k, ans = 99999999, ansid; vector<int> v; void check(int index) { int sum = 0, cnt, flag = 1; scanf("%d", &cnt); set<int> s; vector<int> v(cnt); for (int i = 0; i < cnt; i++) { scanf("%d", &v[i]); s.insert(v[i]); } for (int i = 0; i < cnt - 1; i++) { if(e[v[i]][v[i+1]] == 0) flag = 0; sum += e[v[i]][v[i+1]]; } if (flag == 0) { printf("Path %d: NA (Not a TS cycle)\n", index); } else if(v[0] != v[cnt-1] || s.size() != n) { printf("Path %d: %d (Not a TS cycle)\n", index, sum); } else if(cnt != n + 1) { printf("Path %d: %d (TS cycle)\n", index, sum); if (sum < ans) { ans = sum; ansid = index; } } else { printf("Path %d: %d (TS simple cycle)\n", index, sum); if (sum < ans) { ans = sum; ansid = index; } } } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { int t1, t2, t; scanf("%d%d%d", &t1, &t2, &t); e[t1][t2] = e[t2][t1] = t; } scanf("%d", &k); for (int i = 1; i <= k; i++) check(i); printf("Shortest Dist(%d) = %d\n", ansid, ans); return 0; }
二刷代码
一刷的代码写的太复杂了,二刷的时候显然思想更加成熟了。
//可以采用传统的图的方法!
//数组下标从1开始
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 0x3fffffff;
const int maxn = 500;
int n,m;
int G[maxn][maxn];
int res=inf;
int idx=-1;
int main(){
scanf("%d %d",&n,&m);
fill(G[0],G[0]+maxn*maxn,inf);
for(int i=0;i<m;i++){
int u,v,dis;
scanf("%d %d %d",&u,&v,&dis);
G[u][v]=dis;
G[v][u]=dis;
}
int k;
scanf("%d",&k);
for(int i=0;i<k;i++){
int len;
scanf("%d",&len);
int path[maxn];
for(int j=0;j<len;j++){
scanf("%d",&path[j]);
}
//找到起点
int start=path[0];
int end=path[len-1];
bool vis[maxn]={false};//设置为false
bool isConnect = true;
vis[start]=true;
int ans=0;
for(int j=1;j<len;j++){
int u,v;
u=path[j-1];
v=path[j];
if(G[u][v]!=inf){
ans+=G[u][v];
vis[v]=true;
}else{
isConnect=false;
break;
}
}
if(!isConnect){
printf("Path %d: NA (Not a TS cycle)\n",i+1);
}else{
int cnt=0;
for(int j=1;j<=n;j++){
if(vis[j]==true){
cnt++;
}
}
if(!(start==end&&cnt==n)){
printf("Path %d: %d (Not a TS cycle)\n",i+1,ans);
}else{
if(len==n+1){
printf("Path %d: %d (TS simple cycle)\n",i+1,ans);
}else{
printf("Path %d: %d (TS cycle)\n",i+1,ans);
}
if(ans<res){
idx=i+1;
res=ans;
}
}
}
}
printf("Shortest Dist(%d) = %d",idx,res);
return 0;
}