洛谷P1347 排序html
讲真,我认为题面是有一点问题的:node
题目中有这样一些语句“若根据前x个关系即发现存在矛盾(如A<B,B<C,C<A),输出:Inconsistency found after 2 relations.” 和 “提示:肯定n个元素的顺序后便可结束程序,能够不用考虑肯定顺序以后出现矛盾的状况”c++
首先,那个输出应该是“Inconsistency found after x relations.”算法
其次,已知\(A<B,B<C\),根据那个提示咱们能够直接判断\(A<B<C\)而后后面的\(C<A\)则能够不用管了,可是题目解释的倒是不合法编程
以上是个人想法,我在编程中按照提示编的(AC了),因此题意争议大概不影响作题?(大雾...)数组
好了,废话很少说,这道题我会用两种作法完成:拓扑排序、变种Floyd学习
由于题目中的规则就是元素之间的顺序而且是有向图(仍是无并列关系的顺序),因此可使用拓扑排序.net
由于要求输出第\(i\)步要么完成排序要么造成环,因此每输入一组大小关系就要进行一次拓扑排序code
这题之因此是蓝题,大概就是由于每次拓扑排序须要处理三种状况:
1. 造成合法拓扑序列
2. 造成非法的环
3. 暂时没有造成完整的拓扑序列但也不是环
(注意拓扑排序不处理题目中的第三种状况,即没法肯定的状况)
题目中的第三种状况是最简单的:当输入完成后尚未输出则说明没法肯定出拓扑序列
下面重点讲拓扑排序中的三种状况
①输入的两个元素\(u\)、\(v\)相同(自环)
②答案数组的长度\(<\)目前所出现过的元素个数(下面会给出说明)
①不知足以上造成环的条件
②答案数组的长度\(==N\)(标准的拓扑排序合法判断)
①在最开始入队时,同时存在多个入度为0的点
②在循环队列处理中,有超过1个的点在同一轮入队
答案数组的长度\(<\)目前所出现过的元素个数(造成环),如图:
在最开始入队时,同时存在多个入度为0的点(暂时不造成)
由于题目已经说明拓扑序列没有并列关系,因此这题一个合法的序列不可能同时存在两个源点(即入度为0的点)
同上,由于没有并列关系,因此一个点的后继应该只有一个而不是多个,那么一次只能入队一个,若是一次入队多个则说明当前还不造成合法序列
注释版配合上面的讲解,敲详细呀qwq~
#include <bits/stdc++.h> using namespace std; queue<int> q; char a,b,op; vector<int> ans; int n,m,tot,sum,in[1001],inn[1001],head[1001],flag[1001]; struct node { int to,net; } e[1001]; inline void add(int u,int v) { e[++tot].to=v; e[tot].net=head[u]; head[u]=tot; } inline int check() { //拓扑排序 ans.clear(); //必定要清空 int k=0,kk=0; for(register int i=1;i<=n;i++) { inn[i]=in[i]; //由于队列处理会影响in[],因此要赋值 if(in[i]==0&&flag[i]==1) { if(k==0) k=1; else kk=1; //若是kk=1,则说明同时存在多个入度为0的点 q.push(i); } } if(q.empty()) return 1; //队列为空,说明是环 while(!q.empty()) { int k=0,now=q.front(); //这里k要从新赋为0 q.pop(); ans.push_back(now); //存入答案数组 for(register int i=head[now];i;i=e[i].net) { int v=e[i].to; if(--inn[v]==0) { if(k==0) k=1; else kk=1; //若是kk=1,则说明一次入队多个点 q.push(v); } } } if(ans.size()<sum) return 1; //答案数组的长度<目前出现过的全部元素,造成环 if(kk==1) return 2; return 0; } int main() { scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++) { cin>>a>>op>>b; if(a==b) { //自环的状况 printf("Inconsistency found after %d relations.",i); return 0; } add(a-'A'+1,b-'A'+1); //连边 in[b-'A'+1]++; //后者的入度++ if(flag[a-'A'+1]==0) sum++; //统计当前出现过的不重复的元素个数 if(flag[b-'A'+1]==0) sum++; flag[a-'A'+1]=flag[b-'A'+1]=1; int x=check(); if(x==1) { //环的状况 printf("Inconsistency found after %d relations.",i); return 0; } if(ans.size()==n&&x==0) { //造成了合法的拓扑序列 printf("Sorted sequence determined after %d relations: ",i); for(register int i=0;i<ans.size();i++) cout<<char(ans[i]+'A'-1); printf("."); return 0; } } printf("Sorted sequence cannot be determined."); //最终的无解状况 return 0; }
由于我本人是用的是拓扑排序,而变种Floyd是右边dalao作出来的,因此这里直接挂出dalao的题解