3047: 【普及+/提高】【P1347】排序
题目描述
输入
第一行有两个正整数 , 表示需要排序的元素数量,,第 到 个元素将用大写的 表示。 表示将给出的形如 的关系的数量。
接下来有 行,每行有 个字符,分别为一个大写字母,一个 <
符号,一个大写字母,表示两个元素之间的关系。
输出
若根据前 个关系即可确定这 个元素的顺序 yyy..y
(如 ABC
),输出
Sorted sequence determined after xxx relations: yyy...y.
若根据前 个关系即发现存在矛盾(如 ),输出
Inconsistency found after x relations.
若根据这 个关系无法确定这 个元素的顺序,输出
Sorted sequence cannot be determined.
(提示:确定 个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况)
样例输入 复制
4 6
A<B
A<C
B<C
C<D
B<D
A<B
样例输出 复制
Sorted sequence determined after 4 relations: ABCD.
提示
。
一、思路分析
1、不停的接收结点关系,创建有向图,A->B有边表示 A<B
2、每进入一个结点关系后,判断现在的有向图是否有环,有环就是冲突,提示并退出。判断是否有环可以用拓扑排序,
判断方法是:只要入队(或者出队)的次数不等于节点的个数,就说明有环,有环就是存在矛盾的。
3、在无环的情况下,找到入度为0的点,就是起始点,然后从起始点出发,bfs,看看能不能走出n步,如果能,就是完成了排序工作
二、理解与感悟
1、拓扑排序可以判断有没有环。
2、有环就是表示有循环比大小,就是有冲突。
3、拓扑排序要不断修改入度数组,如果入度数组需要不断建边继续使用,需要复制出来一份才能边建边、边检查拓扑序。
4、单个字符转字符串的办法最好用的是常量字符串的
#include <bits/stdc++.h> using namespace std; const int N = 30; //26个结点是极限 int in[N]; //入度数组 int tmp[N]; //入度临时操作数组 int n; //表示需要排序的元素数量 int m; //表示将给出的形如 A<B 的关系的数量 bool st[N]; //是否使用过 //实在想不出好主意了,用数字转为字符,再拼接到字符串,现在看来最好的办法就是写成一个常量字符串,然后substr去截取 string chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; struct Node { int n; string path; }; //邻接表 vector<int> edge[N]; //拓扑排序,检查是否存在环,有环就是存在矛盾 bool topSort() { //清空状态数组 memset(st, 0, sizeof st); queue<int> q; //拓扑排序用的队列 int sum = 0;//入队列数量 //判断现在是不是有环,有环则退出。入度为0的结点入队列,进行拓扑排序 for (int j = 1; j <= n; j++) if (!tmp[j]) q.push(j); //拓扑排序 while (!q.empty()) { int u = q.front(); q.pop(); sum++; //不是环中结点 st[ u ] = true; //遍历每条出边 for(auto c:edge[ u ]){ if (!--tmp[c]) q.push(c);//在删除掉当前结点带来的入度后,是不是入度为0了,如果是将点y入队列 } } //存在没进过队列的结点,存在表示有环。 return sum < n; } int main() { //读入结点数和边数 cin >> n >> m; //读入关系,建图,边建图边判断 for (int i = 1; i <= m; i++) { string input; cin >> input; char x = input[0], y = input[2];//input[1]='<' 这个是死的,没用 //建图 int a = x - 'A' + 1, b = y - 'A' + 1; edge[a].push_back(b);//建立单边有向图,描述a<b in[ b ]++; //入度数组++ /*****下面的代码是拓扑排序的内容*******************************************************/ //入度数组复制出来一份,因为拓扑排序需要不断的更改入度数组值,后面还需要原始的入度数组,所以需要复制出来一份。 memcpy(tmp, in, sizeof in); bool existCircle = topSort(); if (existCircle) { printf("Inconsistency found after %d relations.", i); exit(0); } /*****拓扑排序结束*********************************************************************/ //到这里应该是无环 //从入度为0的点出发,bfs看看是不是能走完n步,走完说明可以确定所有结点的大小关系,确定了就结束 int cnt = 0; int startNode; for (int j = 1; j <= n; j++) if (!in[j]) startNode = j, cnt++; if (cnt > 1) continue; //存在两个及以上入度为零的点,是无法确定先后顺序的,需要继续读入关系数据 //从startNode出发,看看能不能走出去n轮,如果能,就是可以确定所有结点的顺序,如果不能,就需要继续录入关系才能确定 string path; queue<Node> q; q.push({startNode, chr.substr(startNode - 1, 1)}); //清空状态数组,准备再战! memset(st, 0, sizeof st); while (!q.empty()) { Node u = q.front(); q.pop(); st[ u.n ] = true; if (u.path.size() > path.size())path = u.path; //遍历每条出边 for (auto c:edge[ u.n ]) q.push({c, u.path + chr.substr(c - 1, 1)}); } //如果还存在没访问到的结点,那么就是无法完成排序,需要继续录入关系 if (path.size() < n) continue; //输出路径 printf("Sorted sequence determined after %d relations: %s.", i, path.c_str()); exit(0); } //到达这里说明最终还没有确定下来所有结点关系,提示无法确定。 printf("Sorted sequence cannot be determined."); return 0; }
#include<bits/stdc++.h> using namespace std; #define MAXN 30 int n,m,a,b,ans[MAXN],outd[MAXN],ind[MAXN]; bool u[MAXN]; vector <int> p[MAXN]; string ss,st; struct node { int x,d; }; string get_sequence(int tail) { string ret; if (ans[tail] == 0) { ret +=(tail - 1 + 'A'); return ret; } else { ret +=(tail - 1 + 'A'); return get_sequence(ans[tail]) + ret; } } int check() { queue <node> q; int cnt=0, tot_nodes = 0; memset(ans,-1,sizeof(ans)); for (int i = 1; i <= n; i++) { if (u[i] && ind[i] == 0) { q.push((node){i,1}); ans[i] = 0; } if (u[i]) tot_nodes++; } int maxa=1; int t_ind[MAXN]={0}; for (int i = 1; i <= n; i++) { t_ind[i]=ind[i]; } while (!q.empty()) { node t=q.front(); q.pop(); cnt++; if (outd[t.x] == 0) { maxa=max(maxa,t.d); if (maxa == n) { ss=get_sequence(t.x); return 1; } } for (int i = 0, sz = p[t.x].size(); i < sz ;i++) { t_ind[p[t.x][i]]--; if (t_ind[p[t.x][i]] == 0) { ans[p[t.x][i]] = t.x; q.push((node){p[t.x][i],t.d+1}); } } } if (cnt != tot_nodes) return 2; else return 0; } int main(){ cin >> n >> m; for (int i = 1; i <= m ; i++) { cin >> st; a=st[0]-'A' + 1;b=st[2]-'A' + 1; u[ a ] = true; u[ b ] = true; outd[ a ]++;ind[ b ]++; p[ a ].push_back(b); if (check() == 2) { printf("Inconsistency found after %d relations.",i); return 0; }else if (check() == 1) { cout << "Sorted sequence determined after " << i <<" relations: "; cout << ss <<"."; return 0; } } cout << "Sorted sequence cannot be determined."; return 0; }