高手看了,感觉惨不忍睹——关于“【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原代码:
#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[];
int i,jack,n;
freopen("in.txt","r",stdin);
while(scanf("%d",&jack)!=EOF){
for( i= ; i<max ;i++) {
stu[i]=;
stur[i]=;
}
for( i= ; i< ;i++) {
flag[i]=;
}
for( i= ; ;i++) {
scanf("%d%d",&stu[i],&stur[i]);
if(stu[i]==&&stur[i]==) break;
}
n=i;
for( i= ; i<n ; i++) {
if(jack==stu[i]) {
jack_id=i;
}
}
rank=;
for( i= ; i<n ; i++) {
if((stur[i]>stur[jack_id])&&(flag[stur[i]]!=)){ //找到比自己大的成绩rank++
rank++;
flag[stur[i]]=;
} }
printf("%d\n",rank); } return ;
}
评析:
毛病很多。据原作者说“数据测试了好几个都没问题,可以就是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[];
我在《品悟C》中说过,出现flag的代码,多半早就馊了。(参见:flag标志什么?哦,它标志代码馊了——(一))
while(scanf("%d",&jack)!=EOF){
这个写得还行。问题是原问题特意强调了范围,是否视为long为好?存在这样的可能性:原题的意思是把number作为long处理,把mark作为int处理。当然这只是猜测。
for( i= ; i<max ;i++) {
stu[i]=;
stur[i]=;
}
这里写得很傻。其实只要
while(scanf("%d",&jack)!=EOF){
int stu[max] = {}; //学生的ID
int stur[max]= {}; //学生的成绩
//……
}
就可以了。显然原代码中这两个数组定义的位置不当。
for( i= ; i< ;i++) {
flag[i]=;
}
天知道这是在干什么,很傻很变态。
for( i= ; ;i++) {
scanf("%d%d",&stu[i],&stur[i]);
if(stu[i]==&&stur[i]==) 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[ + ] ;
int sum ;
mark_t jack_m ; sum = input( stu , jack_n , &jack_m ); //输入并获得数据总数及Jack的成绩
printf("%d\n" , rank( stu , sum , jack_m ) );//输出Jack的名次
} system("PAUSE");
return ;
} 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 != || stu->mark != ) //读Jack后面的
stu ++ ; return stu - p_ini ;
} int rank( STD stu[] , int n , mark_t j_m )
{
int r = ;
int i ; for ( i = ; i < n ; i ++ )
if ( stu[i].mark > j_m )
r ++ ; return r ;
}
小结:
input()函数中的两句while很相似,有点难看。改得更漂亮一点怕初学者看不懂,就不改了。
此外,我也不能保证我的代码一定就过,因为我从没刷过题,不清楚刷题的具体规则。
再次重构:
根据 librazy 网友提供的信息:
没记错的话大多数评测机中long 就是long int 就是 int。一般算法竞赛中忘了时空效率考虑都是int(除了很明显需要高精度或ll的。
以及Matrix_R 网友的意见:
不过有个小疑问,就是为什么楼主的函数声明中指针的声明方式都是清一色的[]?为了表明参数是个数组吗?我个人觉得直接用指针更好,更本质。
再次重构代码如下:
#include <stdio.h>
#include <stdlib.h> typedef
struct
{
int num ;
int mark ;
}
STD; int input( STD * , int , int * );
int rank( STD [] , int , int ); int main( void )
{
int jack_n ; while ( scanf( "%d" , &jack_n ) != EOF )
{
STD stu[ + ] ;
int sum ;
int jack_m ; sum = input( stu , jack_n , &jack_m ); //输入并获得数据总数及Jack的成绩
printf("%d\n" , rank( stu , sum , jack_m ) );//输出Jack的名次
} system("PAUSE");
return ;
} int input( STD * p_stu , int j_n , int * p_j_m )
{
STD * p_ini = p_stu ; while ( scanf( "%d%d" , &p_stu->num , &p_stu->mark ) ,
p_stu -> num != j_n ) //读入数据直到Jack的
p_stu ++ ; * p_j_m = p_stu ++ -> mark ; while ( scanf( "%d%d" , &p_stu->num , &p_stu->mark ) ,
p_stu->num != || p_stu->mark != ) //读Jack后面的
p_stu ++ ; return p_stu - p_ini ;
} int rank( STD stu[] , int n , int j_m )
{
int r = ;
int i ; for ( i = ; i < n ; i ++ )
if ( stu[i].mark > j_m )
r ++ ; return r ;
}
高手看了,感觉惨不忍睹——关于“【ACM】杭电ACM题一直WA求高手看看代码”的更多相关文章
- 【ACM】杭电ACM题一直WA求高手看看代码
数据测试了好几个都没问题,可以就是WA不让过,检测了2个小时还是没发现有什么问题T_T!!求高手看看代码,小弟在此谢谢各位哦! #include <stdio.h> #include &l ...
- 杭电acm阶段之理工大版
想參加全国软件设计大赛C/C++语言组的同学,假设前一篇<C和指针课后练习题总结>没看完的,请先看完而且依照上面的训练做完,然后做以下的训练. 传送门:http://blog.csdn.n ...
- 杭电ACM题单
杭电acm题目分类版本1 1002 简单的大数 1003 DP经典问题,最大连续子段和 1004 简单题 1005 找规律(循环点) 1006 感觉有点BT的题,我到现在还没过 1007 经典问题,最 ...
- 杭电acm 1040题
本题是一个非常简单的升序排序题目,但那时在做的时候把题目看错了,导致花费了大量的时间来检查为什么WA,最后发现题目看错了..... /********************************* ...
- 杭电acm 1022题
Problem Description As the new term comes, the Ignatius Train Station is very busy nowadays. A lot o ...
- 杭电acm刷题顺序
最近兴趣来了,闲暇之余,回顾大学期间刷过的杭电acm那些入门级别的题,以此巩固基础知识! 以下参考刷题顺序,避免入坑 原文传送门:https://blog.csdn.net/liuqiyao_01/a ...
- 杭电ACM分类
杭电ACM分类: 1001 整数求和 水题1002 C语言实验题——两个数比较 水题1003 1.2.3.4.5... 简单题1004 渊子赛马 排序+贪心的方法归并1005 Hero In Maze ...
- 杭电ACM(1002) -- A + B Problem II 大数相加 -提交通过
杭电ACM(1002)大数相加 A + B Problem II Problem DescriptionI have a very simple problem for you. Given two ...
- 杭电acm习题分类
专注于C语言编程 C Programming Practice Problems (Programming Challenges) 杭电ACM题目分类 基础题:1000.1001.1004.1005. ...
随机推荐
- The Beginner’s Guide to iptables, the Linux Firewall
Iptables is an extremely flexible firewall utility built for Linux operating systems. Whether you’re ...
- Magento Table Rate运费国家代码汇总
Magento Table Rate是三种内置未调用第三方API运费方式中最强大的一个.通过设置国家,区域,邮编,价格来划分不同的运费等级.该方式基本能够满足轻量级的B2C商城的运费模式.这里收集下国 ...
- Android笔记:利用InputStream和BufferedReader 进行字节流 字符流处理
通过socket获取字节流处理时最初使用的是BufferedReader和PrintWriter 这种方式在解析字符串时是比较方便的 但是在处理字节时不够方便最终还是回归到InputStream和O ...
- jQuery获取自身HTML
<html><head> <title>jQuery获取自身HTML</title> <meta http-equiv="Content ...
- Hibernate 代码生成器
Hibernate 代码生成器 点击Hibernate Code Generation 点击以下 创建管理代码生成配置 点击RUN.自动生成
- JMeter学习-011-JMeter 后置处理器实例之 - 正则表达式提取器(三)多参数获取进阶引用篇
前两篇文章分表讲述了 后置处理器 - 正则表达式提取器概述及简单实例.多参数获取,相应博文敬请参阅 简单实例.多参数获取. 此文主要讲述如何引用正则表达式提取器获取的数据信息.其实,正则表达式提取器获 ...
- linux i2c tools
最近要操作eeprom,所以了解一下i2c-tool的使用方法,记录于此. 参考链接: http://www.myir-tech.com/bbs/thread-7567-1-1.html http:/ ...
- http://tedhacker.top/2016/08/05/Spring%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/
http://tedhacker.top/2016/08/05/Spring%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%9 ...
- JQuery:JQuery语法、选择器、事件处理
JQuery语法: 通过 jQuery,您可以选取(查询,query) HTML 元素,并对它们执行"操作"(actions). 一.语法:jQuery 语法是通过选取 HTM ...
- 30天,O2O速成攻略【8.29杭州站】
活动概况 时间:2015年8月29日13:30-16:30 地点:123茶楼(杭州上城区青年路27号2楼) 主办:APICloud.UPYUN.一起火 网址:www.apicloud.com 费用:免 ...