zoukankan      html  css  js  c++  java
  • 高手看了,感觉惨不忍睹——关于“【ACM】杭电ACM题一直WA求高手看看代码”

    按  

      被中科大软件学院二年级研究生 HCOONa 骂为“误人子弟”之后(见:《中科大的那位,敢更不要脸点么?》 ),继续“误人子弟”。

    问题:

    题目:(感谢 王爱学志 网友对题目给出的翻译)
        排名
    题目要求:
        程序运行时间要不大于1000ms,程序的内存大小不大于32756k.
        向审题系统提交总时间是2843秒,审题系统接受的提交时间是860秒.
    题目描述:
        Jackson想知道他在班级中的排名.教授已经公布班级中人的
        学号和分数的列表.计算Jackson的排名,如果他分数是最高的(包
        括和他分数一样),那么他的排名是1,如果他分数是第二高(包括
        和他分数一样的),那么他的排名是2,等等
    输入:
        输入多个测试用例,以Jackson的学号为输入开始.学号是
        10000000到99999999之间的整数.之后输入所有学生的学号和分数
        .分数是0到100的整数.这个课堂上的学生数不超过1000.每个学生
        的学号是不同的.以输入学号和分数都为0表示输入结束.
    输出:
        通过每个测试用例数据,在新的一行输出Jackson的班级排名
    样例的输入:
        20070101
        20070102 100
        20070101 33
        20070103 22
        20070106 33
    例子的输出:
        2
    题目来源:
        2007省赛集训队练习赛(2)
    推荐:
        ky

    见 :【ACM】杭电ACM题一直WA求高手看看代码

    原代码:

    #include <stdio.h>
    #include <stdlib.h>
    #define max 1000
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    
    int main(int argc, char *argv[]) {
        int  stu[max];   //学生的ID 
        int  stur[max];  //学生的成绩 
        int rank,jack_id; //查找的ID 
        int flag[101];        
        int i,jack,n;
        freopen("in.txt","r",stdin);
        while(scanf("%d",&jack)!=EOF){
            for( i=0 ; i<max ;i++) {
                stu[i]=0;
                stur[i]=0;
            }
            for( i=0 ; i<101 ;i++) {
                flag[i]=1;
            }
            for( i=0 ;  ;i++) {
                scanf("%d%d",&stu[i],&stur[i]);
                if(stu[i]==0&&stur[i]==0) break;
            }
            n=i;
            for( i=0 ; i<n ; i++) {
                if(jack==stu[i]) {
                    jack_id=i;
                }
            }
            rank=1;
            for( i=0 ; i<n ; i++) {
                if((stur[i]>stur[jack_id])&&(flag[stur[i]]!=0)){    //找到比自己大的成绩rank++ 
                    rank++;
                    flag[stur[i]]=0;
                }
                    
            }
            printf("%d
    ",rank);
        
        }
        
        
        return 0;
    }

    评析:

      毛病很多。据原作者说“数据测试了好几个都没问题,可以就是WA不让过”。其实我也不清楚什么原因不过,因为没玩过。只能就其中的错误说一说。并给出改进,但同样不能保证通过,因为我不知道“ACM”的规则。

    #include <stdlib.h>

      不清楚做什么的,没用。

    #define max 1000

      明显违背公序良俗。宏名应该大写。

    int main(int argc, char *argv[]) {

      应该

    int main( void ) {

      代码这东西,你不把它写好就不可能把它写对。

      一main()到底,也是初学者常见的幼稚病,表明根本不懂得如何组织代码。(参见:将main()进行到底)

        int  stu[max];   //学生的ID 
        int  stur[max];  //学生的成绩 

      原作者显然同样不懂得如何组织数据,还处于社会主义初级阶段。
      数组尺寸为max不是不可以,但从后面的代码来看明显错了。应该是 max+1。

        int flag[101];        

      我在《品悟C》中说过,出现flag的代码,多半早就馊了。(参见:flag标志什么?哦,它标志代码馊了——(一))

        while(scanf("%d",&jack)!=EOF){

      这个写得还行。问题是原问题特意强调了范围,是否视为long为好?存在这样的可能性:原题的意思是把number作为long处理,把mark作为int处理。当然这只是猜测。

            for( i=0 ; i<max ;i++) {
                stu[i]=0;
                stur[i]=0;
            }

      这里写得很傻。其实只要

        while(scanf("%d",&jack)!=EOF){
            int  stu[max] = {0};   //学生的ID 
            int  stur[max]= {0};  //学生的成绩 
            //……
        }

      就可以了。显然原代码中这两个数组定义的位置不当。

            for( i=0 ; i<101 ;i++) {
                flag[i]=1;
            }

      天知道这是在干什么,很傻很变态。

            for( i=0 ;  ;i++) {
                scanf("%d%d",&stu[i],&stur[i]);
                if(stu[i]==0&&stur[i]==0) break;
            }

      这里存在越界的可能。有效成绩最多1000个,结束标志0 0 就可能是第1001个。

      从这里向后,已经看不下去了,完全不之所云。不过既然至此已经存在越界错误,也没有必要再看下去了。

      下面给出我的写法:

    重构:

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef long num_t ;
    #define FN "%ld"
    typedef int mark_t ;
    #define FM "%d"
    
    typedef 
       struct 
       {
          num_t  num  ;
          mark_t mark ;   
       } 
    STD;
    
    int input( STD [] , num_t , mark_t * );
    int rank( STD [] , int , mark_t );
    
    int main( void )
    {
      num_t jack_n ;
        
      while ( scanf( FN , &jack_n ) != EOF )
      {
         STD stu[ 1000 + 1 ] ;
         int sum ;
         mark_t jack_m ;
         
         sum = input( stu , jack_n , &jack_m ); //输入并获得数据总数及Jack的成绩 
         printf("%d
    " , rank( stu , sum , jack_m ) );//输出Jack的名次 
      }
      
      system("PAUSE"); 
      return 0;
    }
    
    int input( STD stu[] , num_t j_n , mark_t * p_j_m )
    {
       STD * p_ini = stu ;
        
       while ( scanf( FN FM , &stu->num , &stu->mark ) ,
               stu->num != j_n ) //读入数据直到Jack的 
          stu ++ ;
       
       * p_j_m = stu++ -> mark ;
       
       while ( scanf( FN FM , &stu->num , &stu->mark ) , 
               stu->num != 0 || stu->mark != 0 ) //读Jack后面的
          stu ++ ;
       
       return stu - p_ini ;
    }
    
    int rank( STD stu[] , int n , mark_t j_m )
    {
       int r = 1 ;
       int i ;
    
       for ( i = 0 ; i < n ; i ++ )
          if ( stu[i].mark > j_m  )
             r ++ ;
    
       return r ;
    }

    小结:

      input()函数中的两句while很相似,有点难看。改得更漂亮一点怕初学者看不懂,就不改了。

          此外,我也不能保证我的代码一定就过,因为我从没刷过题,不清楚刷题的具体规则。

    再次重构:

      根据 librazy 网友提供的信息:

    没记错的话大多数评测机中long 就是long int 就是 int。一般算法竞赛中忘了时空效率考虑都是int(除了很明显需要高精度或ll的。

      以及Matrix_R  网友的意见:

    不过有个小疑问,就是为什么楼主的函数声明中指针的声明方式都是清一色的[]?为了表明参数是个数组吗?我个人觉得直接用指针更好,更本质。

      再次重构代码如下: 

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 typedef 
     5    struct 
     6    {
     7       int  num  ;
     8       int  mark ;   
     9    } 
    10 STD;
    11 
    12 int input( STD * , int , int * );
    13 int rank( STD [] , int , int );
    14 
    15 int main( void )
    16 {
    17   int jack_n ;
    18     
    19   while ( scanf( "%d" , &jack_n ) != EOF )
    20   {
    21      STD stu[ 1000 + 1 ] ;
    22      int sum ;
    23      int jack_m ;
    24      
    25      sum = input( stu , jack_n , &jack_m ); //输入并获得数据总数及Jack的成绩 
    26      printf("%d
    " , rank( stu , sum , jack_m ) );//输出Jack的名次 
    27   }
    28   
    29   system("PAUSE");    
    30   return 0;
    31 }
    32 
    33 int input( STD * p_stu , int j_n , int * p_j_m )
    34 {
    35    STD * p_ini = p_stu ;
    36     
    37    while ( scanf( "%d%d" , &p_stu->num , &p_stu->mark ) ,
    38            p_stu -> num != j_n ) //读入数据直到Jack的 
    39       p_stu ++ ;
    40    
    41    * p_j_m = p_stu ++ -> mark ;  
    42    
    43    while ( scanf( "%d%d" , &p_stu->num , &p_stu->mark ) , 
    44            p_stu->num != 0 || p_stu->mark != 0 ) //读Jack后面的
    45       p_stu ++ ;
    46    
    47    return p_stu - p_ini ;
    48 }
    49 
    50 int rank( STD stu[] , int n , int j_m )
    51 {
    52    int r = 1 ;
    53    int i ;
    54    
    55    for ( i = 0 ; i < n ; i ++ )
    56       if ( stu[i].mark > j_m  )
    57          r ++ ;
    58 
    59    return r ;
    60 }

      在此向librazy 和Matrix_R两位网友表示谢意。

  • 相关阅读:
    Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境搭建教程
    将Windows Server 2016 打造成工作站(20161030更新)
    阿里云服务器Svn-Server无法连接
    安卓 webview背景色的设置
    安卓handler、thread实现异步任务
    多幅图像下载的时间效率问题
    gridview里item是textView、Button单击事件相应,以及按下效果的取去除
    android dialog圆角显示及解决出现的黑色棱角.(友情提示)
    Android自定义对话框(Dialog)位置,大小
    安卓selector
  • 原文地址:https://www.cnblogs.com/pmer/p/3463072.html
Copyright © 2011-2022 走看看