TSP 旅行商

THUOJ 数据结构(上)TSP 旅行商


实现思路

建立邻接表

  • 每读入一条边u->v,将其插入u中(后面将实现的tspNode中的边,是以其为出发点的边),并将v的入度+1

    拓扑排序过程中计算最长道路经过的村庄数

  • 算法:零入度拓扑排序,p166 of 数据结构(c++语言版)_邓俊辉
  1. 扫描所有节点,入度为0的入栈
  2. 从栈顶开始,每读一个节点a,扫描其边,相连节点b入度-1,ind变为0的入栈;

    更新b‘路径长度=max(a‘s+1,b‘);更新max路径;

    边界情况处理

  • 由题意

    1 ≤ n ≤ 1,000,000

    0 ≤ m ≤ 1,000,000

    主要边界情况为:路径数量m=0时,此时应该输出1

面向对象

  • 以往做oj题时,只追求运行效率和代码简洁,未按照面向对象思维开发,得不偿失,此次首次尝试面向对象,让我们注重培养计算思维和抽象思维能力吧

    1.实现堆栈模板类stack

ADT
#define DEFAULT_CAPACITY 10
template <typename T>
class stack
{
  private:
    T *st;
    int capacity;
    int top;
    void expand();//未真正实现,集成在了push中
  public:
    //构造函数
    stack(int c = DEFAULT_CAPACITY)//实例化一个容量为c的堆栈
    //析构函数
    ~stack() { delete[] st; }
    int getsize() const { return top; }//top恰为元素个数
    bool empty() { return top == 0; }
    void push(T a);
    T pop();
};

2.tsp节点的ADT

//边表结点
struct edgeNode
{
    int adjvex; // 邻接点域
    struct edgeNode *next;
};

//TSP节点
template <typename T>
class tspNode
{
  public:
    int ind, road;                       //为了方便把ind定义为public了
    void inserte(int i);                 //insert edge 插入指向节点i的边
    int indegree() const { return ind; } //读取入度
    int outdegree() const { return outd; }
    edgeNode *getfirstedge() { return firstedge; }
    //构造函数
    tspNode()
    {
        ind = 0;
        outd = 0;
        road = 1;
        firstedge = NULL;
    }

  private:
    int outd; //outdegree
    edgeNode *firstedge;
};
  • 像数组一样使用模板类
    tspNode<int> *tsp = new tspNode<int>[n + 1];
    delete[] tsp;
    //或形如 tspNode<int> tsp[10];

源代码

tsp.cpp
#include <cstdio>
#include "tsp.h"
const int stackSize = 1000;
int main()
{
    int n, m;

    scanf("%d %d", &n, &m);
    if (m == 0)
    {
        printf("%d\n", 1);
        return 0;
    }
    tspNode<int> *tsp = new tspNode<int>[n + 1];
    int u, v;
    for (int i = 0; i < m; i++)
    {
        scanf("%d", &u);
        scanf("%d", &v); //u->v
        tsp[u].inserte(v);
        tsp[v].ind++;
    } //初始化
    stack<int> stack(stackSize);
    for (int i = 1; i <= n; i++)
    {
        if (tsp[i].indegree() == 0)
            stack.push(i); //遇到入度为0的,将其秩入栈
    }
    int a = 0, b = 0, maxroad = 0;
    edgeNode *p;
    while (!stack.empty())
    {
        a = stack.pop();
        p = tsp[a].getfirstedge();
        while (p != NULL)
        {
            b = p->adjvex;
            tsp[b].ind--;
            if (tsp[b].road < 1 + tsp[a].road)
            {
                tsp[b].road = 1 + tsp[a].road;
            }
            if (maxroad < tsp[b].road)
                maxroad = tsp[b].road;
            if ((tsp[b].ind) == 0)
                stack.push(b);
            p = p->next;
        }
        //从栈顶开始,每读一个节点a,扫描其边,相连节点b入度-1,b‘路径长度=max(a‘s+1,b‘)并更新max路,ind变为0的入栈,
    }
    printf("%d\n", maxroad);
    delete[] tsp;
    return 0;
}

tsp.h
#include <cstdio>

//边表结点
struct edgeNode
{
    int adjvex; // 邻接点域
    struct edgeNode *next;
};

//TSP节点
template <typename T>
class tspNode
{
  public:
    int ind, road;                       //为了方便把ind定义为public了
    void inserte(int i);                 //insert edge 插入指向节点i的边
    int indegree() const { return ind; } //读取入度
    int outdegree() const { return outd; }
    edgeNode *getfirstedge() { return firstedge; }

    tspNode()
    {
        ind = 0;
        outd = 0;
        road = 1;
        firstedge = NULL;
    }

  private:
    int outd; //outdegree
    edgeNode *firstedge;
};

template <typename T>
void tspNode<T>::inserte(int e)
{
    edgeNode *s = new edgeNode;
    s->adjvex = e;
    s->next = firstedge;
    firstedge = s;
    outd++;
};

#define DEFAULT_CAPACITY 10
template <typename T>
class stack
{
  private:
    T *st;
    int capacity;
    int top;
    void expand();

  public:
    stack(int c = DEFAULT_CAPACITY)
    {
        st = new T[capacity = c];
        top = 0;
    }
    ~stack() { delete[] st; }
    int getsize() const { return top; }
    bool empty() { return top == 0; }
    void push(T a)
    {
        st[top++] = a;
        if (top == capacity)
        {
            T *oldst = st;
            st = new T[capacity <<= 1];
            for (int i = 0; i < top; i++)
                st[i] = oldst[i];
            delete[] oldst;
        }
    }
    T pop() { return st[--top]; }
};

复杂度分析

  • 邻接表初始化:O(m)
  • 拓扑排序:扫描入度为0的点O(n)
  • 零入度算法:单次操作相当于删除一条边,O(m)
  • 堆栈扩容:分摊不过O(1),总共不过O(n)
  • 结论:时间复杂度O(m+n),空间消耗为邻接表和堆栈,也为O(m+n)

原文地址:https://www.cnblogs.com/yhjd/p/10201809.html

时间: 2024-11-05 06:02:21

TSP 旅行商的相关文章

美国13509个城镇的经纬度和TSP旅行商回路

美国13509个城镇的经纬度和TSP旅行商回路         在网上下载了美国美国13509个城镇的经纬度和TSP旅行商回路(下载网址:http://www.verysource.com/code/3731091_1/usa13509.opt.tour.html),按照网上的结果,13509个城市的回路结果是:19982859.         我认为,下面这个表里面标示的经纬度,第一个城镇经度为81.7827778,纬度为24.552.778:第二个城镇经度为81.0905556,纬度为24

旅行商(n&lt;15)

http://icpc.ahu.edu.cn/OJ/Problem.aspx?id=420 #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <stack> #include <queue> #include <vector> #include <ma

hdoj 3001 Travelling 【3进制+旅行商】

题目:hdoj 3001 Travelling 题意:标准的旅行商加一句话,每个点最多走两次. 分析:状态转移方程一模一样,只是要三进制,因为每个点有三种状态 0 ,1 2 定义状态:dp[st][i] :在状态为 st 时 当前在 i 点的最小花费 转移方程:dp[now][j] = min(dp[now][j],dp[st][i]+mp[i][j]):now是st可以一次转移得到的状态 注意初始化. 分析: #include <cstdio> #include <algorithm&

POJ 2677 Tour 双调旅行商 dp, double+费用流

题目链接:点击打开链接 题意:给定二维平面上的n个点 从最左端点到最右端点(只能向右移动) 再返回到到最右端点(只能向左移动,且走过的点不能再走) 问最短路. 费用流: 为了达到遍历每个点的效果 把i点拆成 i && i+n 在i ->i+n 建一条费用为 -inf 的边,流量为1 这样跑最短路时必然会经过这条边,以此达到遍历的效果. dp :点击打开链接 对于i点 :只能跟一个点相连 -- 1.跟 i-1点相连 2.不跟i-1相连 用dp[i][j] 表示两个线头为 i 和 j 的

18.03.09 vijos1014旅行商简化版

背景 欧几里德旅行商(Euclidean Traveling Salesman)问题也就是货郎担问题一直是困扰全世界数学家.计算机学家的著名问题.现有的算法都没有办法在确定型机器上在多项式时间内求出最优解,但是有办法在多项式时间内求出一个较优解. 为了简化问题,而且保证能在多项式时间内求出最优解,J.L.Bentley提出了一种叫做bitonic tour的哈密尔顿环游.它的要求是任意两点(a,b)之间的相互到达的代价dist(a,b)=dist(b,a)且任意两点之间可以相互到达,并且环游的路

旅行商算法

有一位旅行商,我们暂且称呼他为彪哥. 他需要前往5个城市,所以想要计算出旅程最短的路线. 对于每种路线组合,他都计算出总旅程,再挑选旅程最短的路线. 那么,算法效率的问题来了. 5个城市有120个不同的排列方式,因此需要执行120次操作. 6个城市有720个不同的排列方式,因此需要执行720次操作. 7个城市有5040个不同的排列方式,因此需要执行5040次操作. 20城市有2432902008176640000个不同的排列方式,因此需要执行2432902008176640000次操作. 综上所

dtoi2797 旅行商

题意: camp国有n座城市,由1,2,...,n编号.城市由n–1条双向道路相连.任意两个城市之间存在唯一的道路连通.有m个旅行商,第i个旅行商会从城市ai旅行到城市bi,贩卖ci件商品.已知第i个城市的居民最多购买wi件商品,bobo想知道旅行商们能够卖出商品数量的最大值. n,m<=20000. 题解:      考虑暴力,对于每一个旅行商,将其路径上的所有点都连边,然后跑最大流就可以了.不过边数太多了,会TLE. 那么这没有什么关系,我们可以树剖+线段树,将每个旅行商连向他们所对应的节点

遗传算法的简单应用-巡回旅行商(TSP)问题的求解

上篇我们用遗传算法求解了方程,其中用到的编码方式是二进制的编码,实现起来相对简单很多, 就连交配和变异等操作也是比较简单,但是对于TSP问题,就稍微复杂一点,需要有一定的策略, 才能较好的实现. 这次的TSP问题的题目是: 随机产生10~30个城市,每个城市之间的距离也是随机产生,距离的范围是[1,50],求最优的路径 ========================================================== 下面就是具体的求解,由于我的策略是基于知网上的<一种改进的遗

HDU 3001 Travelling:TSP(旅行商)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意: 有n个城市,m条双向道路,每条道路走一次需要花费路费v.你可以将任意一个城市作为起点出发,然后遍历每一个城市,并保证同一个城市最多经过2次.问你遍历这些城市的最小费用是多少. 题解: 传统的TSP问题中,每个城市只能经过一次,做法为三重for循环,分别枚举城市的state.现在所处位置i.下一步要到达的城市j. 核心Code: 1 memset(dp,-1,sizeof(dp)); 2