POJ 1094 && ZOJ 1060 Sorting It All Out 【拓扑排序入门】

原题链接:http://poj.org/problem?id=1094

同ZOJ 1060:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1060

Sorting It All Out

Time Limit: 1000MS

 

Memory Limit: 10000K

Total Submissions: 21983

 

Accepted: 7574

Description

Anascending sorted sequence of distinct values is one in which some form of aless-than operator is used to order the elements from smallest to largest. Forexample, 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

Inputconsists of multiple problem instances. Each instance starts with a linecontaining two positive integers n and m. the first value indicated the numberof objects to sort, where 2 <= n <= 26. The objects to be sorted will bethe first n characters of the uppercase alphabet. The second value m indicatesthe number of relations of the form A < B which will be given in thisproblem instance. Next will be m lines, each containing one such relationconsisting of three characters: an uppercase letter, the character"<" and a second uppercase letter. No letter will be outside therange of the first n letters of the alphabet. Values of n = m = 0 indicate endof input.

Output

For eachproblem instance, output consists of one line. This line should be one of thefollowing 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 sortedsequence is determined or an inconsistency is found, whichever comes first, andyyy...y is the sorted, ascending sequence. 

SampleInput

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

SampleOutput

Sorted sequence determined after 4 relations: ABCD.

Inconsistency found after 2 relations.

Sorted sequence cannot be determined.

Source

EastCentral North America 2001

算法:图论之拓扑排序。

题意 :   按照升序序列匹配字符串。

                   关于输入:

                                        题目包含一系列的测试样例。

                                        首先在第一行给你两个数字n(n>=2&& n<=26)和m。

                                        n代表一共要匹配n个不同的字符;

                                        m以"A<B"的形式给你m个字符间这样的关系;

                                        那么接下来的m行当然是以"A<B"的形式输入这些关系了。

                                       如果输入0 0,则结束程序。

                 输出:

                                      题目有三种输出形式:

                                      第一:字符的关系产生了矛盾。PS:产生了环

                                                  对于两个字符 'A' 和 'B',如果有一行输入(或者根据前面的输入推出)的 是"A<B",而在第q(1<q<=m)行输入(或者根据输入推出)"A>B".那么就                                                     产生了矛盾。

                                                  输出:Inconsistency found after qrelations.

                                                 比如说题目中的样例2就是这种情况。

                                                  3 2

                                                  A<B

                                                  B<A

                                                  第二行和第一行产生矛盾。(出现了环)

                           注意:对于样例2,其实也是输入无法匹配的情况,但是却没有输出他们  无法匹配,所以在写程序时要注意这两种情况的输出顺序先判断他们是否矛盾,

                                                 如果矛盾就直接输出矛盾,进入下一轮样例。

                                    第二种情况:字符无法匹配成功。

                                                             输出:Sorted sequence cannot be determined.

                                                             例如样例3:26 1

                                                                                  A<Z

                                                             要匹配26个字符,而只输入了两个字符。

                                                           (PS:输入n,则定是要匹配前N个大写字母)。

                                    第三种情况:字符匹配成功:

                                                              输出:Sorted sequence determined after n relations:

                                                              此处按升序输出字符。

                                                              例如样例1的输出:

                                                              Sorted sequencedetermined after 4 relations: ABCD.

拓扑排序:

1     在有向图中选择一个没有前驱(即入度为0)的顶点并输出之。

2     在有向图中删除刚刚输出的顶点及所有以该顶点为尾的弧。

3      图中若不再有入度为0的顶点,则结束;否则转①。

PS:偏序是指集合中仅有部分元素可比较大小(或先后);

     全序是指集合中所有元素均可比较大小(或先后)。

拓扑排序就是由偏序关系得到全序关系。

算法思想来自:课件16有向无环图及其应用。

参考牛人代码:http://blog.163.com/wojiaojason@126/blog/static/1240982842010214105332122/

code一:

//Accepted	228K	0MS	C++	1791B
#include<stdio.h>
#include<string.h>
int map[27][27];
int in_degree[27],cnt[27],sort[27];
int n,m;
char str[4];
int topo()
{
    int i,j;
    int num,flag,now=0,s;
    flag=now=0;
    memset(sort,0,sizeof(sort));
    for(i=1;i<=n;i++) cnt[i]=in_degree[i];
    for(i=1;i<=n;i++)
    {
        num=0;
        for(j=1;j<=n;j++)
        {
            if(cnt[j]==0) { num++; s=j; }//用cnt记录,免得修改了sum数组的值;
        }
        if(num==0) return 0;//如果没有入度为0的点,则表示有环,矛盾
        if(num>1)  flag=1;//只有入度为0的点只有一个,才能排序,易错点:直接return -1;
        sort[now++]=s;//入队
        cnt[s]=-1;//标记已入队
        for(j=1;j<=n;j++)
           if(map[s][j])
              cnt[j]--;//删边
    }
    if(flag) return -1;//
    return 1;
}
int main()
{
    int i,j;
    int ans,sign;
    int u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0 || m==0) break;
        sign=0;//标记结果
        memset(map,0,sizeof(map));
        memset(in_degree,0,sizeof(in_degree));
        for(i=1;i<=m;i++)
        {
            scanf("%s",str);
            if(sign) continue;
            u=str[0]-'A'+1;v=str[2]-'A'+1;
            map[u][v]=1;//字符数字化记录
            in_degree[v]++;//记录入度
            ans=topo();
            if(ans==0)//矛盾
            {
                printf("Inconsistency found after %d relations.\n",i);
                sign=1;
            }
            if(ans==1)//成功排序并且输出
            {
                printf("Sorted sequence determined after %d relations: ",i);
                for(j=0;j<n;j++)
                    printf("%c",sort[j]+'A'-1);
                printf(".\n");
                sign=1;
            }
        }
        if(!sign)//不能排序
        printf("Sorted sequence cannot be determined.\n");

    }
    return 0;
}

易错点分析:(By Kuangbin)

为何入度为0的点的个数num>1不直接返回-1,而是要用flag标记。

反例:对于有环图:A<B、B<C、C<A矛盾。

比如这种图,应该返回0呢

直接返回-1就不对了。虽然现在不矛盾,但是到后面可能就矛盾了  

看下面的输入,如果没有flag则

5 5

A<B

B<C

C<A

Inconsistency found after 4 relations.

但是正确的结果应该是:

5 5

A<B

B<C

C<A

Inconsistency found after 3 relations.


如果实在无法理解图论问题,则可以看我在网上看的另外一个人的代码:

/来源:/http://blog.sina.com.cn/s/blog_5ced353d0100b4xs.html

//AC 184kb 0ms

Ø      思路:按照输入,对给的每个字符都进行一番比较,比如说有n 个字符,那么就要比较出num=n(n-1)/2次不同的"A<B"形式。

Ø      如果匹配成功了,那么一定会有num个不同的"A<B"的形式的字符比较。

Ø      如何比较:因为n<=26,所以设立一个比较数组cmpMap[26][26]用其来存储字母间的大小关系,cmpMap[i][j]=0表示第i个字母和第j个字母大小未定;

            1表示第i个字母小于第j个字母;

            -1表示第i个字母大于第j个字母。

 在题目输入m个字符间的关系前全部赋值为0,表示不知道字符间的关系。

 

关于输入m个(A<B形式)字符间的关系:

Ø      用一个一位数组s[4]来存储。

Ø      假设当前输入为s[3],则若s[0]==s[2],出现矛盾,

Ø      若s[0]!=s[2]且cmpMap[s[0]-'A'][s[2]-'A']==-1,也出现矛盾

Ø      若s[0]!=s[2]且cmpMap[s[0]-'A'][s[2]-'A']==1,s[0]与s[2]已经有序,故不做操作

Ø      若s[0]!=s[2]且cmpMap[s[0]-'A'][s[2]-'A']==0,扫描所有小于s[0]的字母和s[0],下标为i,所有大于s[2]的字母和s[2],下标为j,则若cmpMap[i][j]==1,已排好序,不做操作,若cmpMap[i][j]==0,置cmpMap[i][j]=1,cmpMap[j][i]=-1,num++。

Ø      num为cmpMap中值为1的元素的个数。可知当num==n*(n-1)/2时,全部字母都排好序。(这一点前面已经提及)

Ø      要点:s中存3个字符,故应为char s[4],写成char s[3];出现segmentation fault错误,注意:'\0'。

 

#include <stdio.h>
int cmpMap[26][26],biggerNum[26];
int main()
{
//freopen("in.txt","r",stdin);
       intn,m,i,j,num,q,inconsistency,succeed;
       chars[4];
       while(scanf("%d%d",&n,&m))
       {
              if(n==0&& m==0)
                     break;
              num=0;
              inconsistency=0;
              succeed=0;
              for(i=0;i<n;i++)
                     for(j=0;j<n;j++)
                            cmpMap[i][j]=0;
              for(q=1;q<=m;q++)
              {
                     scanf("%s",s);
                     if(s[0]==s[2]|| cmpMap[s[0]-'A'][s[2]-'A']==-1) // s[0]与s[2]出现矛盾
                     {
                            inconsistency=1;
                            break;
                     }
                     if(cmpMap[s[0]-'A'][s[2]-'A']==1)    //s[0]与s[2]已有序
                            continue;
                     for(i=0;i<n;i++)        //s[0]与s[2]无序
                            if(cmpMap[s[0]-'A'][i]==-1|| (s[0]-'A')==i) //扫描所有小于s[0]的字母和s[0]
                            {
                                   for(j=0;j<n;j++)
                                          if((cmpMap[s[2]-'A'][j]==1|| (s[2]-'A')==j) && cmpMap[i][j]==0)//扫描所有大于s[2]的字母和s[2]
                                          {          //cmpMap[i][j]==0表示第i个字母和第j个字母无序
                                                 cmpMap[i][j]=1;
                                                 cmpMap[j][i]=-1;
                                                 num++;
                                          }
                            }
                            if(num==n*(n-1)/2)  //num==n*(n-1)/2代表所有字母已排序
                            {
                                   succeed=1;
                                   break;
                            }
              }
              if(inconsistency)
                     printf("Inconsistencyfound after %d relations.\n",q);
              elseif(succeed)
              {
                     printf("Sortedsequence determined after %d relations: ",q);
                     //输出排好序的字母序列
                     for(i=0;i<n;i++)
                            biggerNum[i]=0;
                     for(i=0;i<n;i++)
                            for(j=0;j<n;j++)
                                   if(cmpMap[i][j]==1)
                                          biggerNum[i]++;//找出有多少个字母比i大
                     for(i=n-1;i>=0;i--)
                     {
                            for(j=0;j<n;j++)
                                   if(biggerNum[j]==i)
                                   {
                                          printf("%c",'A'+j);
                                          break;
                                   }
                     }
                     printf(".\n");
              }
              else
                     printf("Sortedsequence cannot be determined.\n");
              if(q<m)
                     for(q++;q<=m;q++)
                            scanf("%s",s);
       }
       return0;
}
 
 
 
 
 
 


你可能感兴趣的:(POJ 1094 && ZOJ 1060 Sorting It All Out 【拓扑排序入门】)