POJ1094 Sorting It All Out

Posted lipoicyclic

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1094 Sorting It All Out相关的知识,希望对你有一定的参考价值。

An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B, C, D implies that A < B, B < C and C < D. in this problem, we will give you a set of relations of the form A < B and ask you to determine whether a sorted order has been specified or not.

Input

Input consists of multiple problem instances. Each instance starts with a line containing two positive integers n and m. the first value indicated the number of objects to sort, where 2 <= n <= 26. The objects to be sorted will be the first n characters of the uppercase alphabet. The second value m indicates the number of relations of the form A < B which will be given in this problem instance. Next will be m lines, each containing one such relation consisting of three characters: an uppercase letter, the character "<" and a second uppercase letter. No letter will be outside the range of the first n letters of the alphabet. Values of n = m = 0 indicate end of input.

Output

For each problem instance, output consists of one line. This line should be one of the following three:

Sorted sequence determined after xxx relations: yyy...y.
Sorted sequence cannot be determined.
Inconsistency found after xxx relations.

where xxx is the number of relations processed at the time either a sorted sequence is determined or an inconsistency is found, whichever comes first, and yyy...y is the sorted, ascending sequence.

Sample Input

4 6
A<B
A<C
B<C
C<D
B<D
A<B
3 2
A<B
B<A
26 1
A<Z
0 0

Sample OutputSorted sequence determined after 4 relations: ABCD.

Inconsistency found after 2 relations.
Sorted sequence cannot be determined.

这是翻译过的题目https://www.acwing.com/problem/content/345/

首先要说的是题意描述不太对。如果在矛盾前能成功判断顺序则算成功,在这个前提下优先判断是否矛盾。


这个题的核心是利用Floyd算法构造传递闭包。以1~26代表A~Z。d[i][j]=1表示i对应的字母小于j对应的字母。构造完成后,若存在变量使得d[i][j]=1且d[j][i]=1说明矛盾,如果d[i][j]与d[j][i]有且仅有一个为1说明这条关系是成立的。d[i][j]与d[j][i]都为0的话要么是i或者j对应的字母输入里根本没涉及要么最终无法确定顺序。把所有出现过的字母列出来,按照出度(出边的数目)排序,出度最大的即为最小的字母变量。举个例子:1,2,3,4,5五个数,1小于2,3,4,5,因此出度为4;2小于3,4,5;因此出度为3…依次等差递减且出度和为n(n-1)/2。


因此可以确定整体思路:For循环每读取到一条关系,先把读取到的变量对应的数加入vector便于后续统计操作,在d数组里令d[a][b]=1(a为小的字母对应的数…),然后跑Floyd(代码在蓝书P360)。这里要注意的是:1.在Floyd里即可判断是否矛盾,如果矛盾直接return false。2.当跑Floyd时出度也会相应变化,因此要注意及时更新。


跑完后如果矛盾直接输出相应语句,吸收掉后面的输入并结束当前TestCase,没有矛盾的话检查当前给出所有关系涉及的字母是否等于n,不等于的话必然没法判断,直接continue,等于的话说明可以判断这些关系能不能确定最终的顺序。用一个结构体存变量对应的字母和出度,遍历vector,确定出度和,如果为(n-1)*n/2则能确定,把结构体按照出度从大到小排序(注意,最大的变量的出度和根本没涉及到的变量的出度都为0,直接排序不可,因此对于每个变量,如果在vector里能找到,则将其出度+1)。输出后吸收掉剩下的输入。如果不能确定的话根据矛盾与否输出对应的语句。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
int n,m;
struct node
{
    int num;//存字母编号
    int out;//存出度 
};
bool floyd(bool d[27][27],struct node nod[])//如果有矛盾 return false; 
{
    int i,j,k;
    for(k=1;k<=26;k++)
    {
        for(i=1;i<=26;i++)
        {
            for(j=1;j<=26;j++)
            {
                /////floyd也要更新出度 dp时出度会变化 
                d[i][j]|=d[i][k]&d[k][j];    
                if(i!=j&&d[i][j]==1&&d[j][i]==1)return false;
            }
        }
    }    
    for(i=1;i<=26;i++)//更新出度 
    {
        int cnt=0;
        for(j=1;j<=26;j++)
        {
            if(d[i][j])cnt++;
        }
        nod[i].out=cnt;
    }
    return true;
}
bool cmp(node a,node b)
{
    return a.out>b.out;
}
int main()
{
    while(scanf("%d%d",&n,&m)&&n&&m)
    {
        int i;
        bool d[27][27]={0};
        bool vis[27]={0};
        int tot_vis=0;//涉及到的变量的个数 
        int contradict=0;//判断是否矛盾的变量 
        int sure=0; //判断能否确定顺序的变量 
        struct node nod[28];//方便输出排序
        for(i=1;i<=26;i++)
        {
            nod[i].num=i;
            nod[i].out=0;
         }     
        vector<int>v;//存储涉及到的变量 
        for(i=1;i<=m;i++)
        {
            char temp[5];
            scanf("%s",temp);
            int a=temp[0]-A+1,b=temp[2]-A+1;
            if(!vis[a])
            {
                vis[a]=1;tot_vis++;v.push_back(a);
            }
            if(!vis[b])
            {
                vis[b]=1;tot_vis++;v.push_back(b);
            }
            d[a][b]=1;//传递的是小于关系 
            nod[a].out++;//出度++    //注意 在floyd时也要更新出度 
            bool pd=floyd(d,nod);
            if(!pd)
            {
                contradict=i;
                int z;
                for(z=i+1;z<=m;z++)//吸收剩下的 
                {
                    char s[5];
                    scanf("%s",s);
                }
                break;
            }
            //当前这一遍如果没有矛盾 判断能否确定关系
            if(tot_vis!=n)//字母都没出现全,肯定没法判断
            {
                continue; 
            }
            else
            {
                int q,w;
                int cnt=0;
                for(q=0;q<v.size();q++)
                {
                    for(w=0;w<v.size();w++)
                    {
                        if(q!=w&&(d[v[q]][v[w]]==1&&d[v[w]][v[q]]==0))cnt++;
                    }
                }
                if(cnt==v.size()*(v.size()-1)/2)//能确定 
                {
                    sure=i;//标记确定 把sure变量赋值为第i次确定 
                    int z;
                    for(z=i+1;z<=m;z++)//吸收剩下的 
                    {
                        char s[5];
                        scanf("%s",s);
                    }
                    break;
                }
                else//不能确定 
                {
                    continue;
                } 
             } 
        }
        if(sure)//能确定
        {
            printf("Sorted sequence determined after %d relations: ",sure);
            int z; 
            //输出序列  注意最后一个的出度为0 会和其他没出现过的字母混杂在一起 所以加一再排序
            vector<int>::iterator it;
             for(z=1;z<=n;z++)
             {
                 if((it=std::find(v.begin(),v.end(),nod[z].num))!=v.end())nod[z].out++;
             }
            sort(nod+1,nod+26+1,cmp);
            for(z=1;z<=n;z++)putchar(A+nod[z].num-1);
            putchar(.);//不要忘记句点 
            cout<<endl;     
        } 
        else
        {
            if(contradict)
            {
                printf("Inconsistency found after %d relations.
",contradict);
             } 
            //if(contradict==0&&tot_vis!=n)//不矛盾且推断不出 
            else
            {
                cout<<"Sorted sequence cannot be determined."<<endl;
            }    
        }
    }    
}

 

以上是关于POJ1094 Sorting It All Out的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1094 Sorting It All Out(拓扑排序判环)

POJ 1094: Sorting It All Out( 拓扑排序 )

POJ1094 Sorting It All Out

POJ 1094 Sorting It All Out

poj1094 Sorting It All Outfloyd传递闭包拓扑序

POJ 1094 Sorting It All Out