Abstract
这篇题解主要介绍了拓扑排序的唯一性问题和存在性问题。
Idea
要想解决这题需要考虑到一下两点:
- 拓扑排序的核心思路在于将所有入度为0的点一次加入序列,如果在某一个时刻图中存在多个入度为0的点,那么我们将无法判断它们的先后顺序,此时,拓扑序列就不唯一了。
- 假设有n个点参与拓扑排序,在排序完成以后,我们发现拍好的序列中只有 m(m<n) 个数,怎么回事呢?这说明图中出现了环,如此一来拓扑排序就无法完成了。
考虑到这题给的条件较少 (m<600) ,因此我们可以考虑每加入一个条件就尝试着进行一次拓扑排序,如果当前状态下拓扑排序中出现了环,那么就是矛盾了;如果序列不唯一,那么就需要继续添加条件;如果序列唯一且包含了所有的 n 个字母,那么我们直接结束程序即可。代码实现的细节见下方注释。
Code
#include <bits/stdc++.h>
using namespace std;
int n, m;
int in[30], out[30]; // 记录入度出度
vector<vector<int>> fa; // 记录每个字母的父亲字母
bool vis[30]; // 记录此字母是否已经被访问过
int cnt_now; // 当前已经访问过的字母的数量
int cnt_ruler; // 当前已经使用的关系数目
// 求解当前状态下,序列是否已经确定/出现矛盾
bool solve()
{
int ins[30], outs[30]; // 复制出度入度,一遍进行拓扑排序
memcpy(ins, in, sizeof in), memcpy(outs, out, sizeof out);
queue<int> q;
for (int i = 0; i < n; i++)
{
if (!vis[i]) // 这个字母还没访问过,那么自然不参与排序
{
continue;
}
if (outs[i] == 0)
{
q.push(i);
}
}
vector<int> ans; // 储存已经排好的序列
bool get_unique_ans = 1; // 是否得到唯一的排序
while (!q.empty())
{
if (q.size() > 1) // 当前有超过一个的点出度为0,那么它们的先后顺序是无法判定的
{
get_unique_ans = 0;
}
int u = q.front(); // 常规拓扑排序,没什么好说的
q.pop();
ans.push_back(u);
for (int i = 0; i < fa[u].size(); i++)
{
int v = fa[u][i];
outs[v]--;
if (outs[v] == 0)
{
q.push(v);
}
}
}
if (ans.size() < cnt_now) // 如果排好序的序列的长度小于目前已经访问过的字母的数量,说明出现了自环(矛盾)
{
cout << "Inconsistency found after " << cnt_ruler << " relations.";
return 1;
}
if (cnt_now == n && ans.size() == n && get_unique_ans) // 已经访问所有字母,且得到唯一排序,直接输出结果
{
cout << "Sorted sequence determined after " << cnt_ruler << " relations: ";
for (int i = 0; i < n; i++)
{
char c = char('A' + ans[i]);
cout << c;
}
cout << ".";
return 1;
}
// 既没有矛盾也没有结束,返回false
return 0;
}
int main()
{
cin >> n >> m;
fa.resize(n + 1);
// 拓扑排序基操,没什么好说的
for (int i = 0; i < m; i++)
{
cnt_ruler++;
int x, y;
string text;
cin >> text;
x = int(text[0] - 'A'), y = int(text[2] - 'A');
if (vis[x] == 0)
{
cnt_now++;
vis[x] = 1;
}
if (vis[y] == 0)
{
cnt_now++;
vis[y] = 1;
}
in[x]++, out[y]++;
fa[x].push_back(y);
if (solve()) // 如果得出了矛盾/可解,就直接退出程序
{
return 0;
}
}
cout << "Sorted sequence cannot be determined.";
return 0;
}
标签:cnt,洛谷,vis,int,拓扑,++,排序,P1347 From: https://www.cnblogs.com/carboxylBase/p/18294030