旅行售货员问题(c++)

目描述:某售货员要到若干个城市推销商品,已知各城市之间的路程(或旅费)。他要选定一条从驻地出发,经过每个城市一遍最后回到驻地的路线,使总的路线(或总的旅费最小)。

问题分析:我们根据图的图生成了一棵2叉排列树,这样求最小路程就转换为如何解这棵空间树的问题。我们做过生成排列的题目如果我们穷举一遍,那么自然可以得到我们想要的解,但是这样时间复杂度O(n!),效率低得可怜,所以我们只有来优化他。

如何优化?

首先我们可以用一个记录的方法,用bestc存放当前已经得到的最优解,那么只要我得到当前的解已经超过最优解了,那么剩下的我就可以不用算了;其次:如果对于任意两个城市是无边标记的(即两个城市之间是没有通路的)也不用考虑这个我们做了优化,具体的时间复杂度只能根据问题的规模而定了,接下来就是实现的问题了。(PS:这道题目还可以用记忆搜索,也就是搜索+DP,可以进一步提高效率,不过这里没有实现)

# include <iostream>
using namespace std;
const int NoEdge=-1;
const int MAX=20;

int G[MAX][MAX];
int ans[MAX],x[MAX];
int bestc,cc;

void init(int n)
{
 int i,j,len;

 memset(G,NoEdge,sizeof(G));
 while( cin>>i>>j )
 {
  if( i==0 && j==0 ) break;
  cin>>len;
  G[i][j]=len;
  G[j][i]=len;
 }
 for(i=1;i<=n;i++)  x[i]=i;
 bestc=0x7fffffff;
 cc=0;
}

void Swap( int& i,int& j)
{
 int t=i;
 i=j;
 j=t;
}

void Traveling(int i,int n)
{
 int j;

 if(i==n+1)
 {
  if(G[ x[n-1] ][ x[n] ] != NoEdge && G[ x[n] ][1] != NoEdge &&
  (cc + G[ x[n] ][1] < bestc ) )
  {
   for(j=1;j<=n;j++)  ans[j] = x[j];
      bestc = cc + G[ x[n] ][ 1 ];
  }
 }
 else
 {
  for(j=i;j<=n;j++)
  {
   if( G[ x[i-1] ][ x[j] ] != NoEdge && (cc + G[ x[i-1] ][ x[j] ] < bestc) )
   {
    Swap( x[i],x[j] );
    cc += G[ x[i-1] ][ x[i] ];
    Traveling(i+1,n);
    cc -= G[ x[i-1] ][ x[i] ];
    Swap( x[i],x[j] );
   }
  }
 }
}

void print(int n)
{
 cout<<"最小的旅行费用为:"<<bestc<<endl;
 cout<<"最佳路径是:";
 for(int i=1;i<=n;i++)
  cout<<ans[i]<<"->";
 cout<<ans[1]<<endl;
}

int main()
{
 int n;
   
 while( cin>>n&&n )
 {
  init(n);
  Traveling(2,n);
  print(n);
 }

 return 1;
}
/*
4
1 2 30
1 3 6
1 4 4
2 3 5
2 4 10
3 4 20
0 0
最小的旅行费用为:25
最佳路径是:1->3->2->4->1

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值