旅行售货员问题

#include "cstdio"
#include "queue"
#include "cstring"
#define MAX 20  
#define NoEdge 0
using namespace std;    

int n;  //城市个数
int v[MAX]; //路径

struct Node
{
    int lcost;  //子树费用下界
    int cc;    //当前费用
    int rcost;  //x[s:n-1]中顶点最小出边费用和
    int s;     //根结点到当前结点的路径为x[0:s]
    int *x;    //需要进一步搜索的顶点是x[s+1:n-1]

    //子树费用下界较小的结点出队列
    bool operator < (const Node &node) const
    {
        return lcost > node.lcost;
    }
};

priority_queue<Node> pq;

int TSP(int **a)
{
    int *minOut = new int[n+1];  //最小出边费用
    int min = NoEdge;  
    int minSum = 0;  //最小出边费用和
    int i, j;

    //记录每个顶点的最小出边费用
    for(i=1; i<=n; i++)
    {
        min = NoEdge;
        for(j=1; j<=n; j++)  //如果顶点i与下一个顶点相邻其出边费用更小
            if(a[i][j] != NoEdge && (a[i][j]<min || min==NoEdge))
                min = a[i][j];  //更新最小出边费用
        if(min == NoEdge)
            return NoEdge;  //没有回路
        minOut[i] = min;   //顶点i的最小出边费用
        minSum += min;     //最小出边费用增加
    }

    //初始化
    Node E;
    E.s = 0;  //顶点编号
    E.x = new int[n];
    for(i=0; i<n; i++)
        E.x[i] = i+1;
    E.cc = 0;       //当前费用
    E.rcost = minSum;  //剩余最小出边费用和

    int best = NoEdge; //最优值

    //搜索解空间树
    while(E.s<n-1)  //当没有到达叶结点时
    {  
        if(E.s==n-2)  //当到达叶结点的父节点时
        {
            //如果下一个结点可达,费用更小,且能与起始结点构成回路
            if(a[E.x[n-2]][E.x[n-1]]!=NoEdge && a[E.x[n-1]][1]!=NoEdge && 
                (E.cc+a[E.x[n-2]][E.x[n-1]]+a[E.x[n-1]][1]<best || best==NoEdge))
            {
                best = E.cc+a[E.x[n-2]][E.x[n-1]]+a[E.x[n-1]][1];  //更新最优值
                E.cc = best;   printf("%d ", best);
                E.lcost = best;
                E.s++;  
                pq.push(E);  //叶结点的父结点入队列
            }
            else
                delete []E.x;  //舍弃扩展结点
        }
        else  //产生扩展结点的儿子结点
        {
            //检查每一个与当前结点相连的结点,将其入队列
            int i;
            for(i=E.s+1; i<n; i++)  //注意这里i != n,因为x[i]中存放的是i+1
            {
                if(a[E.x[E.s]][E.x[i]]!=NoEdge)  //如果下一个顶点可达
                {
                    int cc = E.cc+a[E.x[E.s]][E.x[i]];  //当前费用
                    int rcost = E.rcost - minOut[E.x[E.s]];  //剩余费用
                    int b = cc + rcost;  //最小费用下界

                    if(b<best || best==NoEdge)  //如果可能产生最小费用
                    {
                        Node node;
                        node.cc = cc;  //当前费用
                        node.s = E.s+1;  //顶点编号
                        node.rcost = rcost;  //剩余费用
                        node.lcost = b;  //最小费用下界
                        int j;
                        node.x = new int[n];
                        for(j=0; j<n; j++)
                            node.x[j] = E.x[j];
                        node.x[E.s+1] = E.x[i];  //新结点路径扩展,x[E.s+1],x[i]是下一条边
                        node.x[i] = E.x[E.s+1];  
                        pq.push(node);
                    }
                }   
            }
            delete []E.x;  //完成结点扩展
        }//else结束

        //取下一个扩展结点
        if(pq.empty())
            break;
        E = pq.top(); 
        pq.pop();

    }//while结束

    if(best==NoEdge)  //没有回路
        return NoEdge; 

    //将最优解复制到v[]中
    for(i=0; i<n; i++)
        v[i] = E.x[i];

    //释放所有结点
    while(true)
    {   
        delete []E.x;
        if(pq.empty())
            break;
        E = pq.top();
        pq.pop();   
    }

    return best;
}


int main()
{
    n = 4;
    int **a = new int *[n+1];
    int i, j;
    for(i=0; i<=n; i++)
        a[i] = new int[n+1];
    int b[5][5] = {
        {0, 0,  0,  0, 0},
        {0, 0, 30,  6, 4},
        {0, 30, 0,  5, 10},
        {0, 6,  5,  0, 20},
        {0, 4, 10, 20, 0}
    };

    for(i=0; i<=n; i++)
        for(j=0; j<=n; j++)
            a[i][j] = b[i][j];

    printf("城市个数:%d\n", n);
    printf("邻接矩阵:\n");
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
            printf("%d\t", a[i][j]);
        printf("\n");
    }

    int best = TSP(a);          
    printf("最短回路长为:%d\n", best);

    printf("路径为:\n");
    for(i=0; i<n; i++)  
    {  
        printf("%d-->", v[i]); 
    } 
    printf("%d", v[0]);
    printf("\n");
    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值