• 旅行售货员问题


    //回溯法解决旅行售货员问题
    template<class Type>

    class Traveling
    {
    friend Type TSP(int **,int [],int,Type);
    friend void main(void);
    public:
    Type BBTSP(int v[]);
    private:
    void Backtrack(int i);
    int n, //图G的顶点数
    *x, //当前解
    *bestx; //当前最优解
    Type **a, //图G的邻接矩阵
    cc, //当前费用
    bestc, //当前最优值
    NoEdge; //无边标记
    };


    template<class Type>
    void Traveling<Type>::Backtrack(int i)
    {
    if(i==n)
    {
    if(a[x[n-1]][x[n]]!=NoEdge&&a[x[n][1]!=NoEdge&&
    cc+a[x[n-1]][x[n]]+a[x[n]][1]<bestc||bestc==NoEdge))
    for(int j=1;j<=n;j++)
    bestx[j]=x[j];
    bestc=cc+a[x[n-1]][x[n]]+a[x[n]][1];
    }
    else
    {//是否进入左子树?
    for(int j=i;j<=n;j++)

    if(a[x[i-1][x[j]]!=NoEdge&&
    (cc+a[x[i-1][x[j]]<bestc||bestc==NoEdge))
    {
    //搜索子树
    Swap(x[i],x[j]);

    cc+=a[x[i-1][x[i]];
    Backtrack(i+1);
    cc-=a[x[i-1]][x[i]];
    Swap(x[i],x[j]);
    }
    }
    }

    template<class Type>
    Type TSP(Type **a,int v[],int n,Type NoEdge)
    {
    Traveling<Type> Y;
    //初始化Y
    Y.x=new int[n+1];

    //置x为单位排列
    for(int i=1;i<=n;i++)

    Y.x[i]=i;
    Y.a=a;
    Y.n=n;
    Y.bestc=NoEdge;
    Y.bestx=v;
    Y.cc=0;
    Y.NoEdge=NoEdge;
    //搜索x[2:n]的全排列
    Y.Backtrack(2);

    delete []Y.x;
    return Y.bestc;
    }


    template<class Type>
    class MinHeapNode
    {
    friend Traveling<Type>;
    public:
    operator Type() const
    {
    return lcost;
    }
    private:
    Type lcost, //子树费用的下界
    cc, //当前费用
    rcost; //x[s:n-1]中顶点最小出边费用和
    int s, //根结点到当前结点的路径为x[0:s]
    *x; //需要进一步搜索的顶点是x[s+1:n-1]
    };


    template<class Type>
    Type Traveling<Type>::Backtrack(int v[])
    {
    //定义最小堆的容量为1000
    MinHeap<MinHeapNode<Type>> H(1000);

    Type *MinOut=new Type[n+1];
    //计算MinOut[i]=顶点i的最小出边费用
    Type MinSum=0;//最小出边费用和
    for(int i=1;i<=n;i++)

    {
    Type Min=NoEdge;
    for(int j=1;j<=n;j++)
    if(a[i][j]!=NoEdge&&(a[i][j]<Min||Min==NoEdge))
    Min=a[i][j];
    if(Min==NoEdge) return NoEdge;//无回路
    MinOut[i]=Min;

    MinSum+=Min;
    }

    //初始化
    MinHeapNode<Type> E;

    E.x=new int[n];
    for(int i=0;i<n;i++)
    E.x[i]=i+1;
    E.s=0;
    E.cc=0;
    E.rcost=MinSum;
    Type bestc=NoEdge;
    //搜索排列空间树
    while(E.s<n-1)

    {
    //非叶结点
    if(E.s==n-2)

    {
    //当前扩展结点是叶结点的父结点
    //再加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]
    <bestc||bestc==NoEdge))
    {
    bestc=E.cc+a[E.x[n-2]][E.x[n-1]]+a[E.x[n-1]][1];
    E.cc=bestc;
    E.lcost=bestc;
    E.s++;
    H.Insert(E);
    }
    else delete []E.x;
    else
    {
    //产生当前扩展结点的儿子结点
    for(int i=E.s+1;i<n;i++)

    if(a[E.x[E.s]][E.x[i]]!=NoEdge)
    {
    //可行儿子结点
    Type cc=E.cc+a[E.x[E.s]][E.x[i]];

    Type rcost=E.rcost-MinOut[E.x[E.s]];
    Type b=cc+rcost; //下界
    if(b<bestc||bestc==NoEdge)

    {
    //子树可能含最优解
    //结点插入最小堆
    MinHeapNode<Type> N;

    N.x=new int[n];
    for(int j=0;j<n;j++)
    N.x[j]=E.x[j];
    N.x[E.s+1]=E.x[i];
    N.x[i]=E.x[E.s+1];
    N.cc=cc;
    N.s=E.s+1;
    N.lcost=b;
    N.rcost=rcost;
    H.Insert(N);
    }
    }
    delete []E.x;
    }
    try
    {
    H.DeleteMin(E));
    }
    catch(OutOfBounds)
    {
    break;
    }
    }
    if(bestc==NoEdge)
    return NoEdge;
    for(int i=0;i<n;i++)
    v[i+1]=E.x[i];
    while(true)
    {
    delete []E.x;
    try
    {
    H.DeleteMin(E);
    }
    catch(OutOfBounds)
    {
    break;
    }
    }
    return bestc;
    }
    Live together,or Die alone!
  • 相关阅读:
    指针数组与数组指针
    209. 长度最小的子数组
    面试题 05.08. 绘制直线(位运算)
    1160. 拼写单词
    88. 合并两个有序数组
    80. 删除排序数组中的重复项 II(On)
    python自定义异常和主动抛出异常
    类的构造方法1(类中的特殊方法)
    python之判断一个值是不是可以被调用
    主动调用其他类的成员(普通调用和super方法调用)
  • 原文地址:https://www.cnblogs.com/hzhida/p/2354729.html
Copyright © 2020-2023  润新知