推銷員問題


  旅行商問題,即TSP問題(Traveling Salesman Problem)又譯為旅行推銷員問題、貨郎擔問題,是數學領域中著名問題之一。假設有一個旅行商人要拜訪n個城市,他必須選擇所要走的路徑,路徑的限制是每個城市只能拜訪一次,而且最后要回到原來出發的城市。路徑的選擇目標是要求得的路徑路程為所有路徑之中的最小值。

  這是我大二期末數據結構課程設計的題目之一,其是關於圖這種數據結構的。按照其題目大意可以大致理解為一個旅行商,要從自己原本的城市出發,走遍所有的城市最后回到自己原來的城市。在這個問題中的約束是每個城市都只能拜訪一次。目的是求旅行商走一圈得到的最短路徑的大小。

  對於這個問題,普遍有兩種思路。第一種思路是暴力破解法。

  舉個例子。

  

  如圖所示,一共有五個城市其彼此之間相互連通。旅行商要走完一圈回來且不重復,實際上走得路徑的各種可能性也不過是各種城市的排列組合。

ABCDEA、ACBDEA、......等等,按照排列組合來計算共有4!種情況,在這些組合中選取一種距離最短的方式就好了。當城市數為5的時候看起來還好,但是這種暴力排列組合的時間復雜度是很大的,達到了O(n!),所以對於城市數多的情況下,是很難算出結果的。

  第二種,就是貪心法。所謂貪心法,就是每一步都走最短的路徑,且通往的城市是沒有訪問過的。這種方法,可以得到盡可能短的路徑,但是也會出現一種問題,就是局部最優解不一定是整體最優解,你可能一味的貪心得到是這樣的結果,之前走的路都是最短的,但是最后返回原來城市的路徑究極長,顯然就不滿足最短路徑了。我的方法就屬於這種貪心法,廢話不多說了,上代碼。

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# define INF 100000
# define max 100
using namespace std;
//推銷員問題
typedef struct Graph{
    int distance[max][max];//城市與城市之間的距離 
    char place[max];
    int city;//城市的個數 
    int edge;//邊的個數 
}CI,*PCI;//城市 
bool visited[max];//判斷有沒有訪問過該城市
int order[max];//訪問節點的順序 
int  num_vertax(void);//求已經收入頂點集合的頂點的個數 
void init_graph(CI* G);//初始化城市 
void find_bestway(CI*G);//找到最好的路徑
int locate_graph(CI*G,char elem);//找到頂點的下標位置
void show_graph(CI* G);//把圖打印出來 
int main(void)
{
    char elem;
    PCI G=(PCI)malloc(sizeof(CI));
    
    init_graph(G);
    show_graph(G);
    find_bestway(G);
    free(G); 
    system("pause");
    return 0;
 } 
 void init_graph(CI* G)
 {
     int i,j;
     printf("請輸入一共有多少個城市:\n");
     scanf("%d",&(G->city));
     ///初始化城市 
     for(i=0;i<G->city;i++)
     {
         for(j=0;j<G->city;j++)
         {
             if(i==j)
             {
                 G->distance[i][j]=0;
             }
             else
             {
                 G->distance[i][j]=INF;
             }
         }
     }
     printf("請輸入城市的名稱:\n");
     for(i=0;i<G->city;i++)
     {
         cin>>G->place[i];
     }
     ///輸入城市與城市之間的距離
     for(i=0;i<G->city;i++)
     {
         for(j=0;j<G->city;j++)
         {
             if(G->distance[j][i]!=0&&G->distance[j][i]!=INF)
             {
                 G->distance[i][j]=G->distance[j][i];
             }
            else if(i!=j) 
             {
                 
                 printf("請輸入%c城市與%c城市之間的距離:\n",G->place[i],G->place[j]);
                 scanf("%d",&G->distance[i][j]);
             }
         }
      } 
      
 }
 void find_bestway(CI* G)
 {///找到最好的路徑並輸出出來 
     char begin;//開始的城市
     int start;//開始城市的下標
    int end;//結束城市的下標 
    int remain;//記錄下標 
    int count=1;//計數器
    int cost=0;//花費
    int next;
    int min_cost=0;//總的最小花費 
    for(int i=0;i<G->city;i++)//初始化所有城市都沒有訪問過 
    {
        visited[i]=false;
    }
    for(int i=0;i<max;i++)//順序序號數組我們用-1初始化 
    {
        order[i]=-1;
    }
     cout<<"請輸入您想從哪個城市出發"<<endl;
    cin>>begin;
    start=locate_graph(G,begin);
    cout<<"start="<<start<<endl;
    //開始的那一座城市聲明已經訪問過了
    remain=start;
    cout<<"remain="<<remain<<endl;
    visited[start]=true;
    order[0]=start;//訪問順序的第一個位置裝着該下標
    while(num_vertax()<G->city)
    {
    //    cout<<"有"<<num_vertax()<<"個頂點已經加入"<<endl; 
        cost=INF;//初始化最大長度
        for(int i=0;i<G->city;i++)//在與它相鄰的所有節點中
        {
             if(start!=i&&visited[i]==false&&G->distance[start][i]<cost)
             {
             //    cout<<"start="<<start<<endl;
             //    cout<<"i="<<i<<endl;
             //    cout<<"distance="<<G->distance[start][i]<<endl;
                 cost=G->distance[start][i];
             //    cout<<"第"<<"i="<<i<<"時候"<<cost<<endl; 
                 next=i;
                 
             }            
        } 
        //cout<<"start="<<start<<" ";
        start=next;
         visited[start]=true;//下一個開始的節點為訪問過了
         order[count]=start;
         cout<<"cost="<<cost<<endl;
         min_cost=min_cost+cost;
         count++; 
    }
    
    //cout<<"之前min_cost="<<min_cost<<endl;
    order[count]=order[0];
    //cout<<"最后一段路為:"<<G->distance[count-1][remain]; 
    //cout<<"remain="<<remain<<endl;
    //cout<<"最后節點下標為"<<order[count]<<endl;
//    cout<<"count="<<count; 
    //cout<<"last="<<G->distance[count][remain];
    min_cost=min_cost+G->distance[order[count-1]][remain];
    cout<<"最佳訪問順序為:"<<endl;
    for(int i=0;i<G->city+1;i++)
    {
        cout<<G->place[order[i]]<<" ";
    }
    cout<<endl;
    cout<<"最短的距離為:"<<endl;
    cout<<min_cost;
     cout<<endl;
       
    
    
      
     
 } 
int locate_graph(CI* G,char elem)//返回節點所在的下標 
{
    int i;
    for( i=0;i<G->city;i++)
    {
        if(elem==G->place[i])
        {
          return i;
        }
    }
    
    
} 
int  num_vertax(void)//可以知道頂點集合之中一共有多少個頂點 
{ 
    
    int count=0;
    while(order[count]!=-1)
    {
        count++;
    }
    return count;
}
void show_graph(CI* G)//將圖的內容打印出來
{
    int i,j;
    printf("圖的內容為:\n");
    for(i=0;i<G->city;i++)
    {
        printf("%c\t",G->place[i]);
     }
    printf("\n");
    for(i=0;i<G->city;i++)
    {
        for(j=0;j<G->city;j++)
        {
            printf("%d\t",G->distance[i][j]);
        }
        printf("\n");
     } 
} 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM