THUOJ 数据结构(上)TSP 旅行商
- 点击查看题目:TSP旅行商
实现思路
建立邻接表
- 每读入一条边u->v,将其插入u中(后面将实现的tspNode中的边,是以其为出发点的边),并将v的入度+1
拓扑排序过程中计算最长道路经过的村庄数
- 算法:零入度拓扑排序,p166 of 数据结构(c++语言版)_邓俊辉
- 扫描所有节点,入度为0的入栈
- 从栈顶开始,每读一个节点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