第一次接触到的拓扑序列的题。尝试了邻接表和邻接矩阵+深搜两种写法,后者是紫书的方法。邻接表的方法是考察每个点的入度,邻接矩阵的方法是通过深搜找到每条路径的终点,将它比喻为结果的话,它的父结点就是它的依附条件,同理推下去,每次深搜得到的点都应该放在当前拓扑序列的队首。
题目链接:UVa 10305
AC代码:
邻接表解法:
#include <iostream>
#include <list>
#include <queue>
using namespace std;
class Graph
{
int v;
list<int>* adj; //邻接表
queue<int> q; //维护一个入度为0的顶点集合
int* indegree;
public:
Graph(int v);
~Graph();
void addEdge(int v, int w); //添加边
void topo(); //拓扑排序
};
Graph::Graph(int v) {
this->v = v;
adj = new list<int>[v + 1];
indegree = new int[v + 1];
for (int i = 1; i <= v; i++) //入度初始化为0
indegree[i] = 0;
}
Graph::~Graph() {
delete[] adj;
delete[] indegree;
}
void Graph::addEdge(int v, int w) { //v是起点,w是终点
adj[v].push_back(w);
++indegree[w]; //终点入度加一
}
void Graph::topo() {
for (int i = 1; i <= v; i++)
if (indegree[i] == 0)
q.push(i);
int cnt = 0;
while (!q.empty()) {
int a = q.front(); q.pop();
if (cnt++ != 0)
cout << " ";
cout << a;
for (auto& p : adj[a])
if (!(--indegree[p]))
q.push(p);
}
cout << endl;
}
int main() {
int m, n, v, w;
while (cin >> m >> n && m) {
Graph G(m);
while (n--) {
cin >> v >> w;
G.addEdge(v, w);
}
G.topo();
}
return 0;
}
邻接矩阵+DFS:
#include <iostream>
#include <cstring>
#include <list>
using namespace std;
const int maxn = 200;
bool G[maxn][maxn], visit[maxn]; //邻接矩阵和访问标志
int n, m;
list<int> topo;
void dfs(int task) {
for (int i = 1; i <= n; i++)
if (!visit[i] && G[task][i]) {
visit[i] = true;
dfs(i);
topo.push_front(i); //先存入“结果”,后存入“条件”
}
}
int main() {
int v, w;
while (cin >> n >> m && n) {
memset(G, false, sizeof(G));
memset(visit, false, sizeof(visit));
for (int i = 0; i < m; i++) {
cin >> v >> w;
G[v][w] = true;
}
for (int i = 1; i <= n; i++)
if (!visit[i]) {
visit[i] = true;
dfs(i);
topo.push_front(i);
}
cout << topo.front();
topo.pop_front();
while (!topo.empty()) {
cout << " " << topo.front();
topo.pop_front();
}
cout << endl;
}
return 0;
}