Luogu P1347 排序【拓扑排序】

44 篇文章 0 订阅

在这里插入图片描述

思路:

每输入一个关系就拓扑一次
把结果分为三种情况

1.

根据前x个关系得到整体关系
这里我们可以用拓扑把度清零,记录每个字母都出现过
并且判断最长的链是多少就行了
f [ a [ i ] . t o ] = max ⁡ ( f [ a [ i ] . t o ] , f [ p [ h ] ] + 1 ) , s = max ⁡ ( s , f [ a [ i ] . t o ] ) ; f[a[i].to]=\max(f[a[i].to],f[p[h]]+1),s=\max(s,f[a[i].to]); f[a[i].to]=max(f[a[i].to],f[p[h]]+1),s=max(s,f[a[i].to]);
如果最长链小于n,那么就没有得到整体关系

2.

根据前x个关系判断是否存在矛盾,
这里只要判断实际就是判断有没有出现环即可。

3.

根据这m个关系无法确定这n个元素的顺序
如果1和2都没有成立,那么就是第3个条件

注意

输入一次就要判断一次a和c是否重复,
因为如果出现 a < a a<a a<a 这种情况也会出现矛盾

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;

int d[100010],d2[100010],ls[100010],dl[100010],v[100010],ans[10010],len;
int n,m,tot,hd=0,tl=0;
char aa,b,c;

struct node
{
	int y,next;
}a[100010];
void ljb(int x,int y)
{
	a[++tot]=(node){y,ls[x]};
	ls[x]=tot;
}
void tp()
{
	memset(ans,0,sizeof(ans));
	memset(v,0,sizeof(v));
	hd=0,tl=0,len=0;
	for(int i=1; i<=n; i++)
	   d[i]=d2[i];
	for(int i=1; i<=n; i++)
	 if(d[i]==0)
	   dl[++tl]=i,v[i]=1,ans[i]=1;
	while(hd<tl)
	 {
	 	hd++;
	 	int y=dl[hd];
	 	for(int i=ls[y]; i; i=a[i].next)
		 {
		 	int yy=a[i].y;
		 	if(v[yy]==1)
		 	  continue;
		 	ans[yy]=max(ans[yy],ans[y]+1);
		 	len=max(len,ans[yy]);
		 	d[yy]--;
		 	if(d[yy]==0)
		 	  dl[++tl]=yy,v[yy]=1;
		 }
	 }
}
int main()
{
    cin>>n>>m;
    for(int i=1; i<=m; i++)
     {
     	cin>>aa>>b>>c;
     	if(aa==c)
     	 {
     	   cout<<"Inconsistency found after "<<i<<" relations.";
     	   return 0;
     	 }
     	ljb(aa-64,c-64);
     	d2[c-64]++;
     	tp();
     	if(len==n)
     	 {
    	    cout<<"Sorted sequence determined after "<<i<<" relations: "; 
   	 	    for(int j=1; j<=n; j++)
       	       cout<<char(dl[j]+64);
       	    cout<<".";
       	    return 0;
     	 }
     	for(int j=1; j<=n; j++)
         {
     	   if(d[j]!=0)
     	    {
     	 	   cout<<"Inconsistency found after "<<i<<" relations.";
     	 	   return 0;
            }
         }
     }
    cout<<"Sorted sequence cannot be determined.";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值