P1347 排序(拓扑排序)

排序

题目传送门

解题思路

这题虽然是一道蓝题,但他的数据很小,所以,我们可以每输入一个关系就拓扑一次
我们可以把结果分为三种情况

1.根据前x个关系得到整体关系

这里我们可以用拓扑把度清零,记录每个字母都出现过
并且判断最长的链是多少就行了
f[a[i].to]=max(f[a[i].to],f[p[h]]+1);//找最长链 s=max(s,f[a[i].to]);
如果最长链小于n,那么就没有得到整体关系
提问
那么就有人问了,为什么得不到呢,难道不是经过拓扑后都为0,并且n个字母都出现过就行了吗?
回答
我们拿个样例来讲
4 6
C C B C D A 按照预处理,形成一个这样的DAG(有向无环图)

1.C→D
2.C→D
   ↘
      B 
3.C→D
   ↘
      B→A
当我们执行到第三步时,所有字母都出现过,并且经过拓扑排序,所有度都会为0,
但是答案却错了,因为D与B之间没有大小关系,最长链为C<B<A,长度<n
所以,要判断最长链是否等于n      

接下来,就是输出的问题
我们可以建邻接表,最小的为根,最大的为叶
这样,最先出队(也就是度为0)的字母就是最小的字母

if(s==n)//判断最长链是否为n,第一种情况
{
	cout<<"Sorted sequence determined after "<<i<<" relations: ";
	for(int j=1;j<=t;j++)cout<<char(p[j]+65);//按出队顺序输出
	cout<<".";
	return 0;
} 

2.根据前x个关系即发现存在矛盾

这里,处理就很简单了,只要判断拓扑排序后,度是否还是大于0,实际就是判断有没有出现环

ok=1;
for(int j=0;j<n;j++)//判断是否有环
 if(b[j]>0){ok=0;break;}  

3.根据这m个关系无法确定这n个元素的顺序

这里就更简单,如果1和2都没有成立,那么就是第3个条件

注意

还要有个特判
那刚刚的样例讲
4 6
C C B C D A 最后一个是不是A 所以要输出
Inconsistency found after 6 relations.
所以要判断输入的两个字母是否相等

if(x==y)//特判
{
	cout<<"Inconsistency found after "<<i<<" relations.";
	return 0;
}

下面呈上AC代码

AC代码

#include
using namespace std;
char ch;
int n,m,x,y,h,t,s,ok,tot,b[30],c[30],p[30],o[30],f[30],du[30],head[30];
struct node
{
	int to,next;
}a[1005];
void add(int x,int y)//邻接表
{
	a[++tot]=(node){y,head[x]};
	head[x]=tot;
}
void tp()//拓扑排序
{
	h=t=s=0;//初值
	for(int i=0;i<n;i++)//初值
	{
		o[i]=f[i]=0;
		b[i]=du[i];
		if(b[i]==0)p[++t]=i,o[i]=f[i]=1;//开始度为0就是根
	}
	while(h<t)
	{
		h++;
		for(int i=head[p[h]];i;i=a[i].next)
		 if(o[a[i].to]==0)//如果a[i].to的度还没有为0,就循环
		 {
		 	b[a[i].to]--;//度--
		 	f[a[i].to]=max(f[a[i].to],f[p[h]]+1);//找最长链
		 	s=max(s,f[a[i].to]);
		 	if(b[a[i].to]==0)//度为0
		 	{
		 		p[++t]=a[i].to;//入队
		 		o[a[i].to]=1;//标记
		 	}
		 }
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>ch;//输入是字符
		x=ch-65;
		cin>>ch>>ch;
		y=ch-65;
		if(x==y)//特判
		{
			cout<<"Inconsistency found after "<<i<<" relations.";
			return 0;
		}
		add(x,y);//建图
		du[y]++;//度++
		tp();//拓扑
		ok=1;
		for(int j=0;j<n;j++)//判断是否有环
		 if(b[j]>0){ok=0;break;}  
		if(ok==0)//第2种情况
		{
			cout<<"Inconsistency found after "<<i<<" relations.";//注意有.
			return 0;
		}
		if(s==n)//判断最长链是否为n,第1种情况
		{
			cout<<"Sorted sequence determined after "<<i<<" relations: ";
			for(int j=1;j<=t;j++)cout<<char(p[j]+65);//按出队顺序输出
			cout<<".";
			return 0;
		} 
	}
	cout<<"Sorted sequence cannot be determined.";//如果前2种情况都不是,就是第3种
	return 0;
} 

谢谢

你可能感兴趣的:(拓扑排序,动规dp,邻接表)