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

来源:互联网 发布:开淘宝店要多少钱2016 编辑:程序博客网 时间:2024/05/18 23:56

原题链接: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一:

//Accepted228K0MSC++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;}      


原创粉丝点击