旅行商问题(C++)

#include<iostream>
#include<queue>
#include<cstring>
#define N 10
#define INF 1e7
using namespace std;

struct node
{
    int cl;//当前走过的路径长度
    int rl;//剩余结点最小边权值之和
    int zl;//cl+rl,路径长度下界
    int id;//处理的第几个城市 
    int x[N];//记录当前路径
    node() {}
    node(int c,int r,int z,int i)
    {
        cl=c;
        rl=r;
        zl=z;
        id=i;
        memset(x,0,sizeof(x));
    }
};

int m[N][N];//邻接矩阵存储无向带权图
int bestx[N];//最优解路径
int bestl;//最优解长度
int n,M;//城市数目,路径数目
int minv[N];//每个顶点最小边权值
int minsum;//每个顶点最小边权值之和

void init()//初始化,注意初始化和计算函数调用的位置
{
    int i,j;
    for(i=0; i<N; ++i)
        for(j=0; j<N; ++j)
            m[i][j]=INF;
    memset(bestx,0,sizeof(bestx));
    bestl=INF;
}

void cal()//计算每个顶点的最小边权值
{
    minsum=0;
    memset(minv,0,sizeof(minv));
    int temp,i,j;
    for(i=1; i<=n; ++i)
    {
        temp=INF;
        for(j=1; j<=n; ++j)
            if(m[i][j]!=INF&&m[i][j]<temp)
                temp=m[i][j];
        minv[i]=temp;
        minsum+=temp;
    }
}

struct cmp
{
    bool operator() (node n1,node n2)//当前路径长度短的优先级高
    {
        return n1.zl>n2.zl;//最小堆
    }
};

void bfs()
{
    priority_queue<node,vector<node>,cmp> q;
    node temp(0,minsum,minsum,2);//起点已经确定,从第2个景点开始
    int t;
    for(int i=1; i<=n; ++i)
        temp.x[i]=i;//初始化解向量
    q.push(temp);
    node live;//活结点
    while(!q.empty())
    {
        live=q.top();
        q.pop();
        t=live.id;
        if(t==n)//处理到倒数第二个城市
        {
            if(m[live.x[t-1]][live.x[t]]!=INF&&m[live.x[t]][1]!=INF)//满足约束条件,有路径
            {
                if(live.cl+m[live.x[t-1]][live.x[t]]+m[live.x[t]][1]<bestl)//更新最优解
                {
                    bestl=live.cl+m[live.x[t-1]][live.x[t]]+m[live.x[t]][1];
                    for(int i=1; i<=n; ++i)
                        bestx[i]=live.x[i];
                }
            }
            continue;
        }

        if(live.cl>=bestl)//不满足限界条件
            continue;

        for(int j=t; j<=n; ++j) //排列树,j不能定义为整个函数的局部变量,循环过程中会出现混乱
        {
            if(m[live.x[t-1]][live.x[j]]!=INF)//满足约束条件
            {
                int cl=live.cl+m[live.x[t-1]][live.x[j]];
                int rl=live.rl-minv[live.x[j]];
                int zl=cl+rl;
                if(zl<bestl)//满足限界条件
                {
                    temp=node(cl,rl,zl,t+1);
                    for(int k=1; k<=n; ++k)
                        temp.x[k]=live.x[k];
                    swap(temp.x[t],temp.x[j]);
                    q.push(temp);
                }
            }
        }
    }
}

void output()
{
    cout<<"最短路径长度为:"<<bestl<<endl;
    cout<<"最短路径为:";
    for(int i=1; i<=n; ++i)
        cout<<bestx[i]<<"-->";
    cout<<bestx[1]<<endl;
}

int main()
{
    init();
    cout<<"请输入城市数目:";
    cin>>n;
    cout<<"请输入路径数目:";
    cin>>M;
    cout<<"请输入城市间的路径:";
    int i,a,b,c;
    for(i=0; i<M; ++i)
    {
        cin>>a>>b>>c;
        if(c<m[a][b])
        {
            m[a][b]=c;//注意存成对称阵
            m[b][a]=c;
        }
    }
    cal();//计算minv[],minxum
    bfs();
    output();
    return 0;
}

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值