TSP 旅行商
阿新 • • 發佈:2018-12-31
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)