P1347 排序

漂亮小姐姐点击就送:https://www.luogu.org/problemnew/show/P1347

 

题目描述

一个不同的值的升序排序数列指的是一个从左到右元素依次增大的序列,例如,一个有序的数列A,B,C,D 表示A<B,B<C,C<D。在这道题中,我们将给你一系列形如A<B的关系,并要求你判断是否能够根据这些关系确定这个数列的顺序。

输入输出格式

输入格式:

第一行有两个整数n,m,n表示需要排序的元素数量,2<=n<=26,第1到n个元素将用大写的A,B,C,D....表示。m表示将给出的形如A<B的关系的数量。

接下来有m行,每行有3个字符,分别为一个大写字母,一个<符号,一个大写字母,表示两个元素之间的关系。

输出格式:

若根据前x个关系即可确定这n个元素的顺序yyy..y(如ABC),输出

Sorted sequence determined after xxx relations: yyy...y.

若根据前x个关系即发现存在矛盾(如A<B,B<C,C<A),输出

Inconsistency found after 2 relations.

若根据这m个关系无法确定这n个元素的顺序,输出

Sorted sequence cannot be determined.

(提示:确定n个元素的顺序后即可结束程序,可以不用考虑确定顺序之后出现矛盾的情况)

输入输出样例

输入样例#1: 复制
1:
4 6
A<B
A<C
B<C
C<D
B<D
A<B

2:
3 2
A<B
B<A

3:
26 1
A<Z
输出样例#1: 复制
1:
Sorted sequence determined after 4 relations: ABCD.
2:
Inconsistency found after 2 relations.
3:
Sorted sequence cannot be determined.


// luogu-judger-enable-o2
//规定<号方向是连线方向
//是>号就反过来加边

//好吧没有>号,mdzz 

//确定矛盾?
//....终于还是看了题解 
//....一次拓扑并不能完成。。。
//........数据范围这么小,我为什么要求它一次完成呢。?
//真是越来越不想动脑子了。
//脑子日益萎缩 

//想想,怎么确定矛盾呢?
//要先判环再判可不可行!!! 

//根据前x个关系确定矛盾: 
//因为只有26个点,所以直接开二维数组记录关系
//map[a][b]==1表示a<b,否则就没关系 
//如果说现在输入的关系是a<b,
//如果a==b或者是以前出现过b<a(map[b][a]==1),那么就是有矛盾了,输出然后exit(0)就行了 
//否则,跑topsort,如果有环(没有入度为0的点),就还是矛盾的

//否则,没有矛盾,跑topsort时,
//如果入度为0的点>1个,就不能确定关系
//再拓扑过程中,如果删掉一个点后有两个点入度变成0
//那么也不能确定 

//否则,就是没有矛盾,没有环,入度为0的点只有1个
//那就能确定关系了 

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

const int N=205;

int n,m;
bool flag[N];
bool map[N][N];
int rudu[N],ind[N];
int head[N],num_edge;
struct Edge
{
    int u,v,nxt;
}edge[100005];

inline void add_edge(int u,int v)
{
    edge[++num_edge].u=u;
    edge[num_edge].v=v;
    edge[num_edge].nxt=head[u];
    head[u]=num_edge;
}

inline int topsort(int tim)    //return -1是有环,return 0是无法确定,return 1是确定了 
{
    queue<int> que;
    int sum=0;
    bool f1=0,f2=0;
    for(int i='A';i<='Z';++i)
    {
        if(!flag[i])
            continue;
        ind[i]=rudu[i];
        f1=0;
        if(!rudu[i])
        {
            if(!f1)
                f1=1;
            else
                f2=1;
            que.push(i);
        }
    }
    if(que.empty())
        return -1;
    queue<int> rel;
    int now;
    while(!que.empty())
    {
        now=que.front(),que.pop();
        rel.push(now);        //关系队列 
        ++sum;
        f1=0;
        for(int i=head[now],v;i;i=edge[i].nxt)
        {
            v=edge[i].v;
            --ind[v];
            if(!ind[v])
            {
                if(!f1)
                    f1=1;
                else
                    f2=1;
                que.push(v);    //拓扑队列 
            }
//            if(cnt>1)    //一下子更新了两个点,那就判断不出来了 
//                return 0;
        }
    }
//    cout<<sum<<endl;
    for(int i='A';i<='Z';++i)    //判环 
    {
        if(flag[i]&&ind[i])
            return -1;
    }
    if(f2)
        return 0;
    if(sum==n)
    {
        printf("Sorted sequence determined after %d relations: ",tim);
        while(!rel.empty())
        {
            putchar(rel.front());
            rel.pop();
        }
        putchar('.');
        return 1;
    }
}

char s[5];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%s",s);
        if(map[s[2]][s[0]]||s[2]==s[0])
        {
            printf("Inconsistency found after %d relations.",i);
            exit(0);
        }
        map[s[0]][s[2]]=1;
        flag[s[0]]=flag[s[2]]=1;
        ++rudu[s[2]];
        add_edge(s[0],s[2]);
        int a=topsort(i);
        if(a==-1)
        {
            printf("Inconsistency found after %d relations.",i);
            exit(0);
        }
        else if(a==1)
            exit(0);
    }
    puts("Sorted sequence cannot be determined.");
    return 0;
}
丑陋的纯拓扑代码
// luogu-judger-enable-o2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

const int N=2e3+5;

int n,m,now_p;    //now_p记录当前共出现了几个点,用来在拓扑里判环 
bool flag[N];    //标记点出没出现
bool map[N][N];
int rudu[N],ind[N]; 
int head[N],num_edge;
struct Edge
{
    int u,v,nxt;
}edge[N];

inline void add_edge(int u,int v)
{
    edge[++num_edge].v=v;
    edge[num_edge].nxt=head[u];
    head[u]=num_edge;
}

int path[N],tail;
inline int topsort()
{
    queue<int> que;
    int cnt=0;
    bool cant=0;    //用来判断能不能确定顺序 
    for(int i=0;i<26;++i)
    {
        if(flag[i])
        {
            ind[i]=rudu[i];
            if(!rudu[i])
            {
                ++cnt;
                que.push(i);
            }
        }
    }
    if(que.empty())        //没有入度为0的点,就是有环了 
        return -1;
    cant=cnt>1;        //如果flag=1就是有矛盾,但是不能现在就return,因为可能存在环 
    tail=0;
    int now;
    while(!que.empty())
    {
        now=que.front(),que.pop();
        cnt=0;
        path[++tail]=now;
        for(int i=head[now],v;i;i=edge[i].nxt)
        {
            v=edge[i].v;
            --ind[v];
            if(!ind[v])
            {
                que.push(v);
                ++cnt;
            }
        }
        cant|=cnt>1;    //如果删掉点之后更新了多个点,那就不能确定顺序 
    }
    if(tail<now_p)        //目前能确定的点比已经出现的点少,就是有环 
        return -1;
    if(cant)    //不能确定 
        return 0;
    return 1;
}

char s[5],a,b;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%s",s);
        a=s[0]-'A',b=s[2]-'A';
        if(map[b][a]||a==b)
        {
            printf("Inconsistency found after %d relations.",i);
            exit(0);
        }
        if(!flag[a])
        {
            flag[a]=1;
            ++now_p;
        }
        if(!flag[b])
        {
            flag[b]=1;
            ++now_p;
        }
        add_edge(a,b);
        map[a][b]=1;
        ++rudu[b];
        int sta=topsort();
        if(sta==-1)
        {
            printf("Inconsistency found after %d relations.",i);
            exit(0);
        }
        else if(sta&&now_p==n)
        {
            printf("Sorted sequence determined after %d relations: ",i);
            for(int j=1;j<=n;++j)
            {
                putchar(path[j]+'A');
            }
            putchar('.');
            exit(0);
        }
    }
    puts("Sorted sequence cannot be determined.");
    return 0;
}
漂亮的纯拓扑代码
// luogu-judger-enable-o2
//Floyd传递闭包更新关系
//如果一个点和其他点的关系有n-1个,那么它的位置就确定了
//如果所有的点都有n-1个,那么序列就确定了。 

//好处就是不用像拓扑排序一样还要判好几次环
//因为floyd的时候已经把关系更新了
//如果是环的话就是与之关系相反的那个map[][]==1

//首先要明白的是
//只要在这儿跑Floyd的,那么在添加这个新的关系前是不存在环的
//否则不会跑Floyd,否则就退出了!
//原因就是上边的第二部分,Floyd更新了关系数组 

//Floyd真神奇啊。! 

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

const int N=50;

int n,m;
bool flag[N];
int map[N][N];
int path[N],tail;

inline bool floyd()
{
    for(int k=0;k<26;++k)
    {
        for(int i=0;i<26;++i)
        {
            for(int j=0;j<26;++j)
            {
                map[i][j]|=map[i][k]&map[k][j];
            }
        }
    }
    for(int i=0,rank,cnt;i<26;++i)
    {
        rank=cnt=0;
        for(int j=0;j<26;++j)
        {
            if(map[i][j])
                ++rank;
            if(map[i][j]||map[j][i])
            {
                ++cnt;
            }
        }
        if(cnt==n-1)
        {
            tail++;
            path[rank]=i;
        }
    }
    return tail==n;
}

char s[5];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%s",s);
        int a=s[0]-'A',b=s[2]-'A';
        if(map[b][a]||a==b)
        {
            printf("Inconsistency found after %d relations.",i);
            exit(0);
        }
        map[a][b]=1;
        if(floyd()==1)
        {
            printf("Sorted sequence determined after %d relations: ",i);
            for(int i=n-1;i>=0;--i)
            {
                putchar(path[i]+'A');
            }
            putchar('.');
            exit(0);
        }
    }
    puts("Sorted sequence cannot be determined.");
    return 0;
}
不明所以WA掉第一个点的Floyd
原文地址:https://www.cnblogs.com/lovewhy/p/8705605.html