P1347 [ECNA 2001] 排序
code
#include<bits/stdc++.h>
using namespace std;
//"O campeão tem nome, e se chama Charles Oliveira!"
#define int long long
#define endl '\n'
#define ep emplace
#define pob
#define ll long long
#define pb push_back
#define pof pop_front
#define pob pop_back
#define all(a) a.begin(),a.end()
#define rall(a) a.rbegin(),a.rend()
#define mod 998244353
#define MOD 1000000007
#define N 200010
#define INF 1e18
using ld = long double;
using ui = unsigned;
using ull = unsigned long long;
using i128 = __int128;
int check_topo(int n, const vector<vector<int>>& adj, string& res) {
vector<int> in_degree(n, 0);//这里的in_degree里,开始全都初始化为0了
//所以就算是语句中只出现了 A和B,比如说A<B的化,那么A和C都会被输入到q中去
for (int u = 0; u < n; u++) {
for (int v : adj[u]) in_degree[v]++;
}
//每次都要从头统计一次,防止新的命令出现产生了环
queue<int> q;
for (int i = 0; i < n; i++) {
if (in_degree[i] == 0) q.push(i);
}
bool is_undetermined = false;
res = "";
int count = 0;
while (!q.empty()) {
// 关键点:如果队列中超过一个元素,说明有多个起点,顺序不唯一
//比如是3个点ABC,但是只有一条命令A<B,这个时候我们的队列中就只有A和C,这个时候的size就是大于1的
if (q.size() > 1) is_undetermined = true;
int u = q.front();
q.pop();
count++;
res += (char)('A' + u);
for (int v : adj[u]) {
if (--in_degree[v] == 0) {
q.push(v);
}
}
}
// 如果处理的节点数少于 n,说明图中存在环
//不管是只执行了一条语句还是执行了好多条语句,只要没有环的出现,就是count==n的
if (count < n) return 0;
// 如果虽然处理完了 n 个点,但中间出现过分支
if (is_undetermined) return 2;
// 否则,唯一序
return 1;
}
void solve() {
int n, m;
while (cin >> n >> m && (n || m)) {
vector<vector<int>> adj(n);
bool finished = false;
string res;
for (int i = 1; i <= m; i++) {
string s;
cin >> s;
if (finished) continue;
int u = s[0] - 'A';
int v = s[2] - 'A';
adj[u].push_back(v);
int status = check_topo(n, adj, res);
if (status == 0) {
printf("Inconsistency found after %d relations.\n", i);
finished = true;
} else if (status == 1) {
cout << "Sorted sequence determined after " << i << " relations: " << res << "." << endl;
finished = true;
}
}
if (!finished) {
printf("Sorted sequence cannot be determined.\n");
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t=1;
//cin>>t;
while(t--)solve();
}
分析
简单来说就是,给你几个字符串,类似这样的
4 6
A<B
A<C
B<C
C<D
B<D
A<B
要你分析,这个构成的这个关系是不是合法的/违法的/不明确的
如果有着合理的A<B<C<D………………的话就是合法的,如果有出现A<B,B<A的情况就是不合法的,如果
26 1
A<Z
是这样要有26个字母之间的关系,但是命令行不够的话,那就是不明确的
很容易想到拓扑排序
topo函数
因为我们在每一个字符串被传入进来的时候,都要检查一次,所以我们的拓扑函数传入的参数是要带我们建表的数组的
int check_topo(int n, const vector<vector
for (int u = 0; u < n; u++) {
for (int v : adj[u]) in_degree[v]++;
}
每次我们都要统计一下这个表中现在的情况
queue<int> q;
for (int i = 0; i < n; i++) {
if (in_degree[i] == 0) q.push(i);
}
bool is_undetermined = false;
res = "";
int count = 0;
while (!q.empty()) {
// 关键点:如果队列中超过一个元素,说明有多个起点,顺序不唯一
//比如是3个点ABC,但是只有一条命令A<B,这个时候我们的队列中就只有A和C,这个时候的size就是大于1的
if (q.size() > 1) is_undetermined = true;
int u = q.front();
q.pop();
count++;
res += (char)('A' + u);
for (int v : adj[u]) {
if (--in_degree[v] == 0) {
q.push(v);
}
}
}
这个就是经典的topo排序的板子了,中间加了一个这个
bool is_undetermined = false;
res = "";
int count = 0;
1.这个is_undetermined,是用来判断这个是不是不明确的情况
2.res是用来记录结果字符串的,因为题目说,如果这个是合法的话,就要输出这个合法的序列是怎么样的
3.count是用来记录这个拓扑排序最后有几个元素的,如果元素个数小于n个说明成环了,也就是不合法的情况出现了
具体细节处理
疑惑分析1
if (count < n) return 0;
当命令没有完全读完的时候,会不会出现这个情况呢?答案是不会的,假设命令是完整的,就是不会出现像下面这种情况
26 1
A<Z
那么,cnt就永远是n,为什么呢,假设我们是这里例子
4 6
A<B
A<C
B<C
C<D
B<D
A<B
当我们只读了一条语句的时候:vector<vector
所以是return 2;

浙公网安备 33010602011771号