zoukankan      html  css  js  c++  java
  • 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;
    }
     
     
     
     
     
     


  • 相关阅读:
    Linux下select调用引发的血案
    http://www.regexlab.com/zh/regref.htm
    TPL: 一个新的C++正则表达式(regex)库
    Kerneloops为Linux用户与开发人员搭建“oops”报告提交桥梁
    LINUX同步软件rsync原理
    Oops错误
    C03Java同步实践加强班第9周上机任务
    C03Java同步实践加强班第8周上机任务
    关于读书:读XX书是否为时过早,是否有意义
    C++程序设计第八周上机实践项目
  • 原文地址:https://www.cnblogs.com/freezhan/p/2950450.html
Copyright © 2011-2022 走看看