題目:POJ1094
大意:對於N個大寫字母,給定它們的一些偏序關係,要求判斷出經過多少個偏序關係之後可以確定它們的排序或者存在衝突(有環存在,如A<B且B<A),或者所有的偏序關係用上之後依舊無法確定唯一的排序。
利用拓撲排序即可解決這個問題,但由於題目要求的是經過多少個關係之後就可以確定答案,因此每讀入一個關係,就要進行一次拓撲排序。
如果某一次拓撲排序之後可以確定它們的唯一排序或者發現衝突存在,則後面的直接略過。
如果讀入所有關係之後依然無法確定唯一關係,同時也沒有衝突,則輸出不能確定唯一排序。
若拓撲排序的過程中每次僅有一個點入度爲0,則該排序是可以確定的排序,否則若多個點入度爲0,則不知道哪個點先哪個點後。若拓撲排序進行到某一步之後無法再繼續,則說明存在迴路,此時存在衝突( 此時拓撲得到的頂點數<n )。
代碼如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct Edge
{
int pos;
int next;
}edge[405];
int cur;
int neigh[26];
int n, m;
int indegree[26];
int queue[28], front, rear;
int seq[26];
int toposort()
{
int indeg[26];
bool res = false;
front = rear = 0;
for (int i = 0; i < n; ++i)
{
indeg[i] = indegree[i];
if (indeg[i] == 0) queue[rear++] = i;
}
int k = 0;
while (front != rear)
{
if (front + 1 < rear) res = true; //入度爲零的點很多,一定是front + 1,可以拿POJ上面的第二個例子推演(A<B,B<A)
int tmp = queue[front++];
seq[k++] = tmp;
int e = neigh[tmp];
while (e != -1)
{
--indeg[edge[e].pos];
if (indeg[edge[e].pos] == 0) queue[rear++] = edge[e].pos;
e = edge[e].next;
}
}
if (k < n) return -1; //注意,這3個 return 的順序一定不能顛倒
if (res) return 0;
return 1; //既沒有衝突,也沒有大量入度爲零的頂點,說明排好序了
}
int main()
{
char str[5];
int beg, end;
int err, ans;
while (scanf("%d%d", &n, &m) != EOF)
{
if (!n && !m) break;
for (int i = 0; i < n; ++i)
{
indegree[i] = 0;
neigh[i] = -1;
}
cur = 0;
err = ans = -1;
for (int i = 0; i < m; ++i)
{
scanf("%s", str);
if (err != -1 || ans != -1) continue;
beg = str[0] - 'A';
end = str[2] - 'A';
edge[cur].pos = end;
edge[cur].next = neigh[beg];
neigh[beg] = cur;
++cur;
++indegree[end];
int res = toposort();
if (res == 1) ans = i + 1; //ans=i+1是爲了保存第幾個關係使得完全排序
else if (res == -1) err = i + 1; //err=i+1是爲了保存第幾個關係導致衝突
}
if (ans != -1)
{
printf("Sorted sequence determined after %d relations: ", ans);
for (int i = 0; i < n; ++i) putchar('A' + seq[i]);
printf(".\n");
}
else if (err != -1)
{
printf("Inconsistency found after %d relations.\n", err);
}
else
{
printf("Sorted sequence cannot be determined.\n");
}
}
return 0;
}