POJ 1094 Sorting It All Out(拓扑排序)解题报告

2016-07-29 2,928 次浏览 解题报告

题目链接

题目翻译

描述

一个升序序列中不同元素之间可以用带小于号的关系式来从小到大排列元素。例如,有序序列 A, B, C, D 中包含关系 A < B, B < C 和 C < D。在本题中,我们会给你一个形如 "A < B" 的关系集合,请你决定由此构成的有序序列是否唯一。

输入

输入包含多组实例。每组实例的第一行包含两个正整数 n, m,前者表示待排序对象的数量,2 <= n <= 26,待排序对象是字母表中前 n 个大写字母;后者表示题目实例中给出的 "A < B" 形式的关系数量。接下来有 m 行,每行包含一对关系,每对关系由三个字符组成:一个大写字母、一个小于号和另一个大写字母。不会出现超出前 n 个大写字母的数据。当 n = m = 0 时输入结束。

输出

对于每组测试实例,输出一行,每行会是以下三种情况之一:

Sorted sequence determined after xxx relations: yyy...y.
Sorted sequence cannot be determined.
Inconsistency found after xxx relations.

其中 "xxx" 指有序序列被确定或被证明矛盾时已处理的关系数量,"yyy...y" 指最终确定的升序序列。

解题思路

初看题意,很容易想到拓扑排序。然而这道题和普通拓扑排序的不同之处在于,不是读入所有关系后跑一遍拓扑排序,而是对于每一条新加的关系都要跑一遍,因为可能在输出读完之前就能决定拓扑序或证明有环(关系矛盾)。

本题的难点就在于如何处理不同情况的优先级,返回正确的输出结果。

优先级规则:
存在环(关系矛盾)或 拓扑序已确定 > 拓扑序未确定

对于每组关系,如果能证明出现环(关系矛盾)或能确定拓扑序,则可以直接确定结果,无需考虑后续给出的关系。只有处理完所有关系依然没能确定结果时才输出「不确定」。

最后,关于确定拓扑序的实现细节,我们可以在读入关系进行拓扑排序时,检查 n 次循环中,是否每次都能且只能找到 1 个入度为 0 的点,是的话则可以生成确定的拓扑序;如果不能找到满足的点,则无法拓扑排序;如果出现了多个入度为 0 的点,应标记为不确定并继续读入下一组关系做判断。

参考代码

#include <cstdio>
#include <cstring>
#define INCOSISTENT 0
#define DETERMINED 1
#define UNDETERMINED 2
using namespace std;

const int MAXN = 26;
int n, m, cnt, indegree[MAXN], order[MAXN];
bool graph[MAXN][MAXN];

int TopoSort() {
    cnt = 0;
    bool legal;
    int flag = INCOSISTENT;
    int indegree_tmp[MAXN];
    // 复制一份入度数组,防止影响原数组
    memcpy(indegree_tmp, indegree, sizeof(indegree));
    for(int i=0; i<n; ++i) {
        legal = false;
        int in_cnt = 0;
        // 统计当前入度为0的点的个数
        for(int j=0; j<n; ++j) {
            if(indegree_tmp[j] == 0)
                in_cnt++;
        }
        // 如果入度为0的点的个数大于1,标记为未确定
        if(in_cnt > 1) flag = UNDETERMINED;
        for(int j=0; j<n; ++j) {
            if(indegree_tmp[j] == 0) {
                order[cnt++] = j;
                indegree_tmp[j]--;
                for(int k=0; k<n; ++k) {
                    if(graph[j][k])
                        indegree_tmp[k]--;
                }
                legal = true;
                break;
            }
        }
        if(!legal) break;
    }

    if(!legal) return INCOSISTENT;
    else if(legal && flag==UNDETERMINED)
        return UNDETERMINED;
    else return DETERMINED;
}

int main(int argc, char const *argv[]) {
    while(scanf("%d %d", &n, &m), n|m) {
        memset(graph, false, sizeof(graph));
        memset(indegree, 0, sizeof(indegree));
        int ans = UNDETERMINED, checked_cnt = 0;
        char str[4], a, b;
        while(m--) {
            scanf("%s", str);
            // 如果已证明有环或拓扑序已确定,不再处理数据
            if(ans != UNDETERMINED) continue;
            checked_cnt++;
            a = str[0]-'A';
            b = str[2]-'A';
            if(graph[b][a])
                ans = INCOSISTENT;
            // 相同关系第一次出现时才记录
            if(!graph[a][b]) {
                indegree[b]++;
                graph[a][b] = true;
            }
            ans = TopoSort();
        }
        if(ans == INCOSISTENT)
            printf("Inconsistency found after %d relations.\n", checked_cnt);
        if(ans == DETERMINED) {
            printf("Sorted sequence determined after %d relations: ", checked_cnt);
            for(int i=0; i<cnt; ++i) {
                printf("%c", order[i]+'A');
            }
            printf(".\n");
        }
        if(ans == UNDETERMINED) printf("Sorted sequence cannot be determined.\n");
    }
    
    return 0;
}

参考资料


bLue 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。
本文地址:https://dreamer.blue/blog/post/2016/07/29/poj-1094.dream

还不快抢沙发

添加新评论