题目大意:给出几个任务的先后顺序,推出可能的排序。并不一定是唯一的。
解法一:
1,找出没有前驱,且没有访问过的点,放在拓扑序列的头部,,,2,删掉他所有想关连的边,并标记访问过。再次找出没有前驱的点,重复前面两个步骤,直到所有的点都访问过位置,输出拓扑序列。
#include<stdio.h>
#include<string.h>
const int N = 105;
int m, n, x, y, t;
int G[N][N], visit[N], topo[N];
int find() {
int count = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(G[j][i])
count++;
}
if(count == 0 && !visit[i])
return i;
else
count = 0;
}
return -1;
}
void delet(int k) {
visit[k] = 1;
topo[t++] = k;
for(int i = 1; i <= n; i++)
if(G[k][i]) {
G[k][i] = 0;
}
}
int main() {
while(scanf("%d%d", &n, &m) , n || m) {
int i;
t = 0;
memset(G, 0, sizeof(G));
memset(visit, 0, sizeof(visit));
for( i = 0; i < m; i++) {
scanf("%d%d", &x, &y);
G[x][y] = 1;
}
int s = find();
while(s != -1) {
delet(s);
s = find();
}
for(i = 0; i < n; i++)
if(i != n - 1)
printf("%d ", topo[i]);
else
printf("%d\n", topo[i]);
}
return 0;
}
解法二:
s[i]里面存放的是i完成后,才能开始的任务集合; 如果存在环,那么显然不存在拓扑排序。利用dfs来进行拓扑排序,每次将访问结束的结点放在当前拓扑序列的首部。
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 105;
vector<int> s[maxn];
int c[maxn], t;
int topu[maxn];
bool dfs (int k) {
c[k] = -1; //正在访问,判环用的
int len = s[k].size();
int tmp;
for (int i = 0; i < len; i++) {
tmp = s[k][i];
if (c[tmp] == -1) //存在有向环
return false;
else if (!c[tmp] && !dfs(tmp)) //存在有向环
return false;
}
c[k] = 1; //不要忘记访问完之后要将这个结点置位1,表示已经访问过;
topu[t--] = k; //每次访问完改节点,如果没有出现环,那么就将这个结点放在当前拓扑序列的首部(为什么不放在尾部)那是因为可能下次会有一个结点u,存在这个u -> k 的关系,这个时候,如果放在尾部的话,之前的关系是k - > k1->k2->k3,突然出现了u,明显不能接在后面,所以放在首部 k3<-k2<-k1<-k,那么这时候的u放在首部符合要求;
return true;
}
bool topuSort (int n) {
t = n;
memset (c, 0, sizeof(c));
for (int i = 1; i <= n; i++)
if (!c[i] && !dfs(i))
return false;
return true;
}
int main () {
int n, m;
int pre, next;
while (scanf ("%d%d", &n, &m) && (n || m)) {
for (int i = 0; i < maxn; i++)
s[i].clear();
for (int i = 0; i < m; i++) {
scanf ("%d%d", &pre, &next);
s[pre].push_back(next);
}
if (topuSort(n)) {
for (int i = 1; i < n; i++)
printf ("%d ", topu[i]);
printf ("%d\n", topu[n]);
}
}
return 0;
}