旅行商模型

旅行商问题(Traveling Saleman Problem,TSP)又译为旅行推销员问题货郎担问题,简称为TSP问题,是最基本的路线问题,该问题是在寻求单一旅行者由起点出发,通过所有给定的需求点之后,最后再回到原点的最小路径成本。

HDU 4568

     http://acm.hdu.edu.cn/showproblem.php?pid=4568

进出一次,找到所有能找到的宝藏,裸的TSP问题。将整个边界理解成一个点,找到每两个宝藏之间的最短距离和每个宝藏的离边界点的最短距离。

先用spfa预处理出宝藏与宝藏之间的最短距离,宝藏到边界的最短距离,然后就是经典的求TSP过程了。


const   int  Max_N = 208 ;
const   int  Max_K = 15 ;
const   int  inf = (1<<30) ;

struct  Node{
        int x ;
        int y ;
        int step ;
        friend bool operator < (const Node &A , const Node &B){
             return A.step > B.step ;
        }
        Node(){}
        Node(int i , int j , int k):x(i) , y(j) ,step(k){}
};

struct  BaoZhang{
        int  x ;
        int  y ;
};


BaoZhang Bao[Max_K] ;
int Bao_Id[Max_N][Max_N] ;
int  N , M , K ;
int  money[Max_N][Max_N] ;
bool visited[Max_N][Max_N] ;
int  d[4][2] = { {1,0} ,{-1 ,0} ,{0 ,-1} ,{0 ,1} } ;
int  dist[Max_K][Max_K] ;
int  dp[1<<Max_K][Max_K] ;

int  cango(int x , int y){
     return 1 <= x && x <= N && 1 <= y && y <= M ;
}

void  bfs(BaoZhang b , int u){
      priority_queue<Node> que ;
      memset(visited , 0 , sizeof(visited)) ;
      que.push(Node(b.x , b.y , 0)) ;
      visited[b.x][b.y] = 1 ;
      int OK_dot = 0 ;
      while(! que.empty()){
           Node now = que.top() ;
           que.pop() ;
           if(Bao_Id[now.x][now.y] > 0){
                int v = Bao_Id[now.x][now.y] ;
                dist[u][v] = now.step ;
                OK_dot++ ;
           }
           if(dist[u][0] == inf && (now.x == 1 || now.x == N || now.y == 1 || now.y == M) ){
                 dist[u][0] = now.step ;
                 dist[0][u] = now.step + money[b.x][b.y] ;
                 OK_dot++ ;
           }
           if(OK_dot == K+1)
                 return  ;
           for(int i = 0 ; i < 4 ; i++){
                 int x = now.x + d[i][0] ;
                 int y = now.y + d[i][1] ;
                 if(cango(x,y) && money[x][y] != -1 && !visited[x][y]){
                       visited[x][y] = 1 ;
                       que.push(Node(x,y,now.step+money[x][y])) ;
                 }
           }
      }
}

int  TSP(int n){
     int i , j , k , limit ;
     dist[0][0] = 0 ;
     limit = 1<<(n+1) ;
     for(i = 0 ; i < limit ; i++)
        for(j = 0 ; j <= n ; j++)
            dp[i][j] =  inf ;
     for(i = 0 ; i <= n  ; i++)
        dp[1<<i][i] = dist[0][i] ;
     for(i = 0 ; i < limit ; i++){
        for(j = 0 ; j <= n ; j++){
           if(i & (1<<j) == 0)  continue ;
           for(k = 0 ; k <= n ; k++){
                if(i & (1<<k) == 0)  continue ;
                if(dist[k][j] == inf) continue ;
                dp[i][j]  = min(dp[i][j], dp[i^(1<<j)][k] + dist[k][j]) ;
           }
        }
    }
    return dp[limit-1][0] ;
}


int  main(){
     int T , i , j , k;
     scanf("%d" ,&T) ;
     while(T--){
          scanf("%d%d" ,&N ,&M) ;
          for(i = 1 ; i <= N ; i++)
             for(j = 1 ; j <= M ; j++)
                 scanf("%d" ,&money[i][j]) ;
          memset(Bao_Id , -1 , sizeof(Bao_Id)) ;
          scanf("%d" ,&K) ;
          for(i = 1 ; i <= K ; i++){
               scanf("%d%d" ,&Bao[i].x ,&Bao[i].y) ;
               Bao[i].x++ ;
               Bao[i].y++ ;
               Bao_Id[Bao[i].x][Bao[i].y] = i ;
          }
          if(!K){
               puts("0") ;
               continue  ;
          }
          for(i = 0 ; i <= K ; i++)
              for(j = 0 ; j <= K ; j++)
                  dist[i][j] = inf  ;
          for(i = 1 ; i <= K ; i++)
              bfs(Bao[i] , i) ;
          int ans = TSP(K) ;
          if(ans == inf)
               puts("0") ;
          else
               printf("%d\n" ,ans) ;
     }
     return 0 ;
}


POJ 3311

http://poj.org/problem?id=3311

Floyd + TSP

题意是有N个城市(1~N)和一个PIZZA店(0),要求一条回路,从0出发,又回到0,而且距离最短。

const int Max_N = 12 ;
const int inf = (1<<30) ;

int dist[Max_N][Max_N] ;
int N ;
int dp[1<<Max_N][Max_N] ;

void  Floyd(){
      int i , j , k ;
      for(i = 0 ; i <= N  ; i++){
         for(j = 0 ; j <= N ; j++){
              for(k = 0 ; k <= N ; k++){
                   if(dist[i][j] >  dist[i][k] + dist[k][j])
                        dist[i][j] = dist[i][k] + dist[k][j] ;
              }
         }
      }
}

int  DP(){
     int i , j , k ;
     int limit = 1<<(N+1) ;
     for(i = 0 ; i < limit ; i++){
         for(j = 0 ; j <= N ; j++)
            dp[i][j] = inf ;
     }
     for(i = 0 ; i <= N ; i++)
        dp[1<<i][i] = dist[0][i] ;
     for(i = 0 ; i < limit ; i++){
          for(j = 0 ; j <= N ; j++){
              if(i & (1<<j) == 0)  continue ;
              for(k = 0 ; k <= N ; k++){
                 if(i & (1<<k) == 0) continue  ;
                 if(dist[k][j] == inf) continue ;
                 dp[i][j] = min(dp[i][j] , dp[i^(1<<j)][k] + dist[k][j]) ;
              }
          }
     }
     return dp[limit-1][0] ;
}

int  main(){
     int i  , j ;
     while(cin>>N && N){
          for(i = 0 ; i <= N ; i++){
              for(j = 0 ; j <= N ; j++)
                  scanf("%d" ,&dist[i][j]) ;
          }
          Floyd() ;
          printf("%d\n" , DP()) ;
     }
     return 0 ;
}


HDU  4248

http://acm.hdu.edu.cn/showproblem.php?pid=4284


题目:给出一些城市,从1出发,旅游一圈回到1,由于花费可能不够,所以选择一些城市打工,打工之前需要花费d买一个证,工资为c。选中的城市必须去工作一次,而且只能工作一次,问能不能完成旅行.

1:重边:只要取最小的距离就可以
2:从u->v必须要有足够的钱
3:选中的城市必须工作
4:工作前必须先买证才能工作,钱不够不能工作(既不能合并工资和买证而得到受益)


const int Max_N = 108 ;
const int Max_H = 16 ;
const int inf = (1<<29) ;

int  money ;
int  N ;
int  dist[Max_N][Max_N] ;
int  dp[1<<Max_H][Max_H] ;

struct Node{
       int id ;
       int lisence ;
       int makemony ;
       void read(){
            scanf("%d%d%d" ,&id , &makemony , &lisence) ;
       }
}h[Max_H];
int  H ;

void Floyd(){   /*Floyd最精确模板*/
    int i,j,k;
    for(k = 1; k <= N ; k++){
        for(i = 1; i <= N ; i++){
            if(dist[i][k]  == inf)  continue ;
            for(j = 1 ; j <= N ; j++){
                if(dist[k][j] == inf)  continue ;
                dist[i][j] = min(dist[i][j] , dist[i][k] + dist[k][j]);
            }
        }
    }
}

int DP(){
     int i , j , k  , u , v  ;
     int limit = (1<<H) ;
     memset(dp , -1 , sizeof(dp)) ;
     for(i = 0 ; i < H ; i++){
          v = h[i].id ;
          if(money >= dist[1][v] + h[i].lisence)
             dp[1<<i][i] = money - dist[1][v] - h[i].lisence + h[i].makemony ;
     }

     for(i = 1 ; i < limit ; i++){
         for(j = 0 ; j < H ; j++){
              if(dp[i][j] == -1)  continue ;
              if(i & (1<<j) ==0)  continue ;
              u = h[j].id ;
              for(k =0 ; k < H ; k++){
                   if(i & (1<<k))  continue  ;
                   v = h[k].id ;
                   if(dp[i][j] >= dist[u][v] + h[k].lisence){
                       int now = (i ^ (1<<k)) ;
                       dp[now][k] = max(dp[now][k] , dp[i][j] - dist[u][v] - h[k].lisence + h[k].makemony) ;
                   }
              }
         }
     }

     for(i = 0 ; i < H ; i++){
          if(dp[limit-1][i] >= dist[h[i].id][1])
              return 1 ;
     }
     return 0 ;
}

int  main(){
     int T , m , i , j , u , v , w;
     scanf("%d" ,&T) ;
     while(T--){
          scanf("%d%d%d" ,&N ,&m ,&money) ;
          for(i = 1 ; i <= N ; i++){
              for(j = 1 ;  j<= N ; j++)
                   dist[i][j] = (i==j? 0 : inf) ;
          }
          while(m--){
                scanf("%d%d%d" ,&u , &v ,&w) ;
                dist[u][v] = dist[v][u] = min(dist[u][v] , w) ;
          }
          cin>>H ;
          for(i = 0 ; i < H ; i++)
               h[i].read() ;

          Floyd() ;

          if(DP())
             printf("YES\n") ;
          else
             printf("NO\n") ;
     }
     return 0 ;
}


FZU 2120

http://acm.fzu.edu.cn/problem.php?pid=2120

S得到了一个数,他认为相邻位上的数字与数字之间会产生不良影响,比如123,1和2之间产生一个不良影响值,2和3之间产生一个不良影响值。现在他想调整这个数每位的数字的顺序,使得最终得到的数的总的不良影响值最小,且没有前导0。

输入数据的第一行为T表示有T组数据。每组数据先输入一个整数n(0<n<1000000000),接下来输入10*10的矩阵,Aij表示数字i与数字j相邻产生的不良影响值,0<Aij<1000000,矩阵是对称的,Aij与Aji相等。


const int inf = 1<<29 ;

string str ;
int  grid[10][10] ;
int  N ;
int  dp[1<<12][12] ;
int  dist[12][12] ;

int  DP(){
     int i , j , k , limit  , ans = inf ;
     limit = (1<<N) ;
     for(i = 0 ; i < limit ; i++){
         for(j = 0 ; j < N ; j++)
             dp[i][j] = inf ;
     }
     for(i = 0 ; i < N ; i++){
         if(str[i] == '0')
            continue ;
         dp[1<<i][i] = 0 ;
     }
     for(i = 0 ; i < limit ; i++){
         for(j = 0 ; j < N ; j++){
               if(i & (1<<j) == 0)  continue  ;
               for(k = 0 ; k < N ; k++){
                     if(i & (1<<k) == 0)  continue ;
                     dp[i][j] = min(dp[i][j] , dp[i^(1<<j)][k] + dist[k][j]) ;
               }
         }
     }

     for(i = 0 ; i < N ; i++){
          ans = min(ans , dp[limit-1][i]) ;
     }
     return ans ;
}

int  main(){
     int T  , i , j  ;
     cin>>T   ;
     while(T--){
          cin>>str ;
          for(i = 0 ; i <= 9 ; i++){
              for(j = 0  ; j <= 9 ; j++)
                   scanf("%d" ,&grid[i][j]) ;
          }
          N = str.length() ;
          for(i = 0 ; i < N ; i++){
             for(j = 0 ; j < N ; j++)
                  dist[i][j] = grid[str[i]-'0'][str[j]-'0'] ;
          }
          printf("%d\n" ,DP()) ;
     }
     return 0 ;
}




### 回答1: 旅行问题是一个典型的组合优化问题,其目标是找到一条路径,使得旅行从一个点出发经过所有城市一次然后回到起点,使得路径最短。旅行问题应用广泛,涉及到物流、交通、网络规划等领域。 在MATLAB中,我们可以运用图论和遗传算法来解决旅行问题。首先,我们需要使用图论的工具包,例如MATLAB自带的Graph和Digraph函数,来构建城市之间的图。通过设置图的边权重为两个城市之间的距离,可以建立一张完整的城市网络。 然后,我们可以利用遗传算法来求解问题。遗传算法是一种优化算法,通过模拟生物的进化过程,从初始的种群中筛选出最优解。在MATLAB中,可以使用遗传算法工具箱中的函数来实现。 具体而言,我们可以使用遗传算法工具箱中的ga函数,指定问题的目标函数和约束条件,同时设置遗传算法的参数,例如种群大小、迭代次数等。通过多次迭代,遗传算法将逐步优化路径,最终给出一条最优的旅行路径。 在编码实现方面,我们可以使用矩阵来表示城市网络,其中每个元素表示城市之间的距离。通过遗传算法的迭代过程,我们可以对城市网络矩阵进行交叉、变异等操作,从而得到更优的路径。 总之,MATLAB提供了丰富的工具和函数,可以帮助我们解决旅行问题。通过结合图论和遗传算法的方法,可以求解出最短路径,并在各种实际问题中得到应用。 ### 回答2: 旅行商模型(Traveling Salesman Problem,TSP)是一个经典的组合优化问题,其目标是寻找一条路径,使得旅行能够依次访问给定的一系列城市,并回到起始城市,同时使得路径的总长度最短。 在Matlab中,我们可以使用不同的方法来解决旅行问题。其中一种常用的方法是使用遗传算法。遗传算法是一种模拟自然界生物进化过程的优化算法,它通过模拟遗传、交叉、变异等操作来搜索问题的最优解。 在使用Matlab实现旅行商模型时,我们首先需要确定城市之间的距离矩阵。这可以通过计算城市之间的欧氏距离或其他距离度量来实现。 接下来,我们使用遗传算法的框架来解决旅行问题。首先,我们随机生成一个初始种群,其中每个个体表示一条可能的路径。然后,我们使用适应度函数来评估每个个体的路径长度,将个体的适应度值作为选择的依据。 根据适应度值,我们进行选择、交叉和变异操作,生成下一代种群。选择操作可以根据适应度值的大小选择某些个体作为优秀个体,并保留其路径信息。交叉操作将两个个体的路径信息进行交叉,生成新的个体。变异操作则在个体的路径中进行一定的改变,以增加搜索的多样性。 通过多次进行选择、交叉和变异操作,我们逐渐优化种群的路径,并找到最优解。最终,我们可以得到一条最优路径,使得旅行能够经过每个城市,并回到起始城市的总距离最短。 总之,Matlab可以通过使用遗传算法的思想和框架来解决旅行问题。使用适应度函数评估个体路径的长度,选择、交叉和变异操作优化种群,并最终获得最优路径。这样,我们可以通过Matlab实现旅行商模型的求解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值