PAT甲级1150Travelling Salesman Problem

题目链接

https://pintia.cn/problem-sets/994805342720868352/problems/1038430013544464384

题解

题目要求

  • 现在给你一些环,请你找到其中与旅行商问题答案最接近的那个环(旅行商问题的定义在此不再说明)
  • 输入
    • N:大于2,不超过200,城市的数量
    • M:无向图中边的数量,
    • M条边:每条边表示为City1 City2 Dist,其中城市索引为[1,N],城市间距离为不超过100的正数
    • K:正整数,path的数量
    • K条path:每条path的格式为:n c1 c2 c3 … cn,其中n是path中城市的数量,ci是城市索引
  • 输出
    • 对于每条path,输出Path X: TotalDist (Description),其中X是[1,K],TotalDist是总距离(不存在则输出NA),Description是
      • 经过每个城市的简单环:TS simple cycle
      • 经过每个城市的环,但不是简单环:TS cycle
      • 不是经过每个城市的环:Not a TS cycle
    • 最终输出Shortest Dist(X) = TotalDist,其中X是和旅行商问题解最接近的那个环的索引,TotalDist是其距离总和。(已确保只有一个解)

解题思路

  • 距离用二维数组表示,默认值为0,为0则说明两个城市间不存在边

  • 读取每条path时,用一维数组存储某个节点被访问的次数(注意城市索引是1到N)

    在路径合法的前提下

    • TS cycle:即经过每个城市并且是一个环,即每个城市被访问的次数都大于0且首尾城市相同
    • TS simple cycle:在TS cycle的基础上,要求没有子环,只有起点城市被访问过2次,其它城市都只被访问过一次
  • 将k个path的结果存放在一维数组中

代码

// Problem: PAT Advanced 1150
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/1038430013544464384
// Tags: Graph TSP

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int distances[205][205]; // 各个城市之间的距离。如果为0,则说明两个城市间无边、不可直达

int main()
{
    int n, m, k;
    scanf("%d %d", &n, &m);

    int c1, c2, dist;
    for (int i = 0; i < m; i++){ // 存储各个城市之间的距离
        scanf("%d %d %d", &c1, &c2, &dist);
        distances[c1][c2] = distances[c2][c1] = dist;
    }

    int bestX, bestDist = INT_MAX;
    scanf("%d", &k);
    for(int x = 1; x <= k; x++){
        vector<int> visited(n + 1, 0);
        int numOfCities, firstCity, pathTotalDist = 0;
        bool pathIslegal = true;
        scanf("%d %d", &numOfCities, &firstCity);
        visited[firstCity] += 1; // 访问第一个城市
        c1 = firstCity; // 更新上一个城市

        for(int i = 0 ; i < numOfCities - 1; i++){
            scanf("%d", &c2); // 读取当前城市
            if (distances[c1][c2] != 0){
                visited[c2] += 1;
                pathTotalDist += distances[c1][c2]; // 计算该路径的总距离
            }
            else{ // path中两个城市不存在边
                pathIslegal = false;
            }
            c1 = c2; // 更新上一个城市
        }

        if (!pathIslegal){ // 路径非法
            printf("Path %d: NA (Not a TS cycle)\n", x);
            continue;
        }

        if (firstCity != c2){ // 在路径合法的前提下,第一个城市和最后一个城市不同,则该路径不是环
            printf("Path %d: %d (Not a TS cycle)\n", x, pathTotalDist);
            continue;
        }

        bool isTS = true;
        for (int i = 1; i < n + 1; i++){
            if (visited[i] < 1){
                isTS = false;
                break;
            }
        }
        if (!isTS){ // 该路径没有经过所有城市
            printf("Path %d: %d (Not a TS cycle)\n", x, pathTotalDist);
            continue;
        }

        bool isSimple = true;
        for (int i = 1; i < n + 1; i++){ // 已确保是环且经过所有城市,判断是否是简单环,并更新最短TS环路
            if (pathTotalDist < bestDist){
                bestX = x;
                bestDist = pathTotalDist;
            }

            if (i != firstCity && visited[i] > 1){
                isSimple = false;
            }
        }

        if (isSimple)
            printf("Path %d: %d (TS simple cycle)\n", x, pathTotalDist);
        else
            printf("Path %d: %d (TS cycle)\n", x, pathTotalDist);
    }

    printf("Shortest Dist(%d) = %d\n", bestX, bestDist);
    return 0;
}

作者:@臭咸鱼

转载请注明出处:https://www.cnblogs.com/chouxianyu/

欢迎讨论和交流!


posted @ 2020-09-05 13:07  臭咸鱼  阅读(121)  评论(0编辑  收藏  举报