1. 程式人生 > >1150 Travelling Salesman Problem

1150 Travelling Salesman Problem

1150 Travelling Salesman Problem(25 point(s))

The “travelling salesman problem” asks the following question: “Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city and returns to the origin city?” It is an NP-hard problem in combinatorial optimization, important in operations research and theoretical computer science. (Quoted from “

https://en.wikipedia.org/wiki/Travelling_salesman_problem“.)

In this problem, you are supposed to find, from a given list of cycles, the one that is the closest to the solution of a travelling salesman problem.

Input Specification:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2

Sample Input:

6 10
6 2 1
3 4 1
1 5 1
2 5 1
3 1 8
4 1 6
1 6 1
6 3 1
1 2 1
4 5 1
7
7 5 1 4 3 6 2 5
7 6 1 3 4 5 2 6
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 2 5 4 3 1
7 6 3 2 5 4 1 6

Sample Output:

Path 1: 11 (TS simple cycle)
Path 2: 13 (TS simple cycle)
Path 3: 10 (Not a TS cycle)
Path 4: 8 (TS cycle)
Path 5: 3 (Not a TS cycle)
Path 6: 13 (Not a TS cycle)
Path 7: NA (Not a TS cycle)
Shortest Dist(4) = 8

//AC code 
/*
  1:輸入資料,用鄰接矩陣儲存邊
  2:讀入一條待測路v[i],並插入 set<int> s;
  3: 遍歷待測路徑,sum 統計有效路徑長度,並用 flag 標記是否有路徑不可達,若不可達,及時跳出 
  4:ok,現在開始列舉可能出現結果:
     (1):: falg== 0 ,即路徑不合法 
     (2):: flag== 1 ,存在路徑首位不同(有去無回 ) 或者 路徑中規定景點沒逛到(偷工減料) 
     (3):: 到此步,說明逛了一圈且規定景點都逛了,滿足旅行商環路的條件,路徑合法 
           再判斷是否走了n+1各節點(是否存在一個景點光了兩次)
  5: 輸出最短合法路徑長度 
  6:注意格式輸出 
*/
#include<iostream> 
#include<vector>
#include<set>
#include<climits>
using namespace std;

int e[300][300],n, m, k, ans = INT_MAX,ans_id;
vector<int> v;

void check(int index){
    int sum=0,cnt;
    cin>>cnt;
    set<int>s;
    vector<int>v(cnt);
    for (int i=0;i<cnt;i++){
        scanf("%d",&v[i]);
        s.insert(v[i]); 
        //插入自動排序,並刪除重複元素 
        /*set集合容器實現了紅黑樹的平衡二叉檢索樹的資料結構,
         它會自動調整二叉樹的排列,把元素放到適當的位置。
         set容器所包含的元素的值是唯一的,集合中的元素按一定的順序排列。
        用迭代器訪問測試 : 
        set<int>::iterator it;
        for(it=s.begin() ;it!=s.end() ;it++)
           cout<<(*it)<<" ";
        */ 
    }
    bool flag=true; // flag 用於標記是否存在不可達路徑  
    for (int i=0;i<cnt-1;i++){
        if(e[v[i]][v[i+1]]== 0){
            flag=false; break; // 跳出節省時間 
        }
        sum+=e[v[i]][v[i+1]];
    }
    if(flag==false){ 
        cout<<"Path "<<index<<": NA (Not a TS cycle)"<<endl; 
    }else if(v[0]!=v[cnt-1] || s.size()!= n){ 
        cout<<"Path "<<index<<": "<<sum<<" (Not a TS cycle)"<<endl; 
    }else if(cnt!=n+1){  
        cout<<"Path "<<index<<": "<<sum<<" (TS cycle)"<<endl;
        if (sum<ans){
            ans=sum;
            ans_id=index; 
        }
    } else{ //源點訪問兩次,simple cycle 
        cout<<"Path "<<index<<": "<<sum<<" (TS simple cycle)"<<endl;
        if (sum<ans){
            ans =sum;
            ans_id=index;
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=0;i<m;i++) {
        int c1,c2,c;
        cin>>c1>>c2>>c;
        e[c1][c2]=e[c2][c1]=c;
    }
    cin>>k;
    for(int i=1;i<=k;i++) check(i);
    cout<<"Shortest Dist("<<ans_id<<") = "<<ans<<endl;
    return 0;
}