1004 成绩排名 (20分)
读入 n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号。
输入格式:
每个测试输入包含 1 个测试用例,格式为
第 1 行:正整数 n
第 2 行:第 1 个学生的姓名 学号 成绩
第 3 行:第 2 个学生的姓名 学号 成绩
... ... ...
第 n+1 行:第 n 个学生的姓名 学号 成绩
其中姓名和学号均为不超过 10 个字符的字符串,成绩为 0 到 100 之间的一个整数,这里保证在一组测试用例中没有两个学生的成绩是相同的。
输出格式:
对每个测试用例输出 2 行,第 1 行是成绩最高学生的姓名和学号,第 2 行是成绩最低学生的姓名和学号,字符串间有 1 空格。
输入样例:
3
Joe Math990112 89
Mike CS991301 100
Mary EE990830 95
输出样例:
Mike CS991301
Joe Math990112
原题链接
思考
- 用结构体记录学生的姓名、学号、成绩,用temp存放临时成绩、
- max_ans存放最高分数学生,min_ans存放最低分数学生,并对其成绩分别初始化为-1和101
- 通过遍历存储判断即可得出答案
#include <stdio.h>
struct student{
char name[15];
char id[15];
int score;
}temp,max_ans,min_ans; //temp存放临时成绩,max_ans为最高分成绩学生,min_ans为最低分成绩学生
int main(){
int n,i;
max_ans.score=-1; //最高分初试成绩
min_ans.score=101; //最低分初始成绩101
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s %s %d",temp.name,temp.id,&temp.score);
if(temp.score>max_ans.score) max_ans=temp;
if(temp.score<min_ans.score) min_ans=temp;
}
printf("%s %s\n",max_ans.name,max_ans.id);
printf("%s %s\n",min_ans.name,min_ans.id);
return 0;
}
1028 人口普查 (20分)
某城镇进行人口普查,得到了全体居民的生日。现请你写个程序,找出镇上最年长和最年轻的人。
这里确保每个输入的日期都是合法的,但不一定是合理的——假设已知镇上没有超过 200 岁的老人,而今天是 2014 年 9 月 6 日,所以超过 200 岁的生日和未出生的生日都是不合理的,应该被过滤掉。
输入格式:
输入在第一行给出正整数 N,取值在(0,10^5];随后 N 行,每行给出 1 个人的姓名(由不超过 5 个英文字母组成的字符串)、以及按 yyyy/mm/dd(即年/月/日)格式给出的生日。题目保证最年长和最年轻的人没有并列。
输出格式:
在一行中顺序输出有效生日的个数、最年长人和最年轻人的姓名,其间以空格分隔。
输入样例:
5
John 2001/05/12
Tom 1814/09/06
Ann 2121/01/30
James 1814/09/05
Steve 1967/11/20
输出样例:
3 Tom John
原题链接
思考
- 输入在第一行给出正整数 N(N<=100000)
- 随后 N 行,每行给出 1 个人的姓名(由不超过 5 个英文字母组成的字符串)、以及按 yyyy/mm/dd(即年/月/日)格式给出的生日。
- 题目保证最年长和最年轻的人没有并列。
- 顺序输出有效生日的个数、最年长人和最年轻人的姓名.
- 今天是 2014 年 9 月 6 日,所以超过 200 岁的生日和未出生的生日都是不合理的,应该被过滤掉。
- 直接以结构体存储、自定义字符串排序函数,按要求输入输出即可
注意
- 可能一个有效生日都没有,这时候直接输出0。
AC1
#include <stdio.h>
typedef struct census{
char name[11]; //姓名
char date[11]; //生日
}census;
int cmp(const void *a, const void *b){ //字符排序函数
census A= *(census*) a;
census B= *(census*) b;
return strcmp(A.date,B.date);
}
int main(){
int N,i,count=0;
scanf("%d",&N);
census str[100010];
char names[11],dates[11];
for(i=0;i<N;i++){
scanf("%s %s",names,dates);
if(strcmp(dates,"2014/09/06")<=0 && strcmp("1814/09/06",dates) <= 0){ //没有超过 200 岁的
strcpy(str[count].name,names); //合法的名字存储到结构体
strcpy(str[count].date,dates); //合法的日期存储到结构体
count++; //计数
}
}
qsort(str,count,sizeof(str[0]),cmp);
if(count) printf("%d %s %s",count,str[0].name,str[count-1].name);
else printf("0"); //一个有效生日都没有
return 0;
}
AC2
#include <stdio.h>
int main() {
int N, count=0,i;
char str[17], max[17] = {'9'}, min[17] = {'0'};
scanf("%d", &N);
for(i = 0; i < N; i++) {
scanf("%s %s", str + 11, str);
if(strcmp(str, "1814/09/06") >= 0 && strcmp(str, "2014/09/06") <= 0) {
if(strcmp(str, max) <= 0)
memcpy(max, str, 17);
if(strcmp(str, min) >= 0)
memcpy(min, str, 17);
count++;
}
}
if(count) printf("%d %s %s", count, max + 11, min + 11);
else printf("0");
return 0;
}
1020 月饼 (25分)
月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。
注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有 3 种月饼,其库存量分别为 18、15、10 万吨,总售价分别为 75、72、45 亿元。如果市场的最大需求量只有 20 万吨,那么我们最大收益策略应该是卖出全部 15 万吨第 2 种月饼、以及 5 万吨第 3 种月饼,获得 72 + 45/2 = 94.5(亿元)。
输入格式:
每个输入包含一个测试用例。每个测试用例先给出一个不超过 1000 的正整数 N 表示月饼的种类数、以及不超过 500(以万吨为单位)的正整数 D 表示市场最大需求量。随后一行给出 N 个正数表示每种月饼的库存量(以万吨为单位);最后一行给出 N 个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分隔。
输出格式:
对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后 2 位。
输入样例:
3 20
18 15 10
75 72 45
输出样例:
94.50
原题链接
题意
- 现有月饼需求量为D,已知n种月饼各自的库存量和总售价,问如何销售这些月饼,使得可以获得的收益最大。求最大收益。
思考
- 步骤1:这里采用“总是选择单价最高的月饼出售,可以获得最大的利涠“的策略。因此,对每种月饼,都根据其库存量和总售价来计算出该种月饼的单价。之后,将所有月饼按单价从高到低排序。
- 步骤2:从单价高的月饼开始枚举。
- 1.如果该种月饼的库存量不足以填补所有需求量,则将该种月饼全部卖出,此时需求量减少该种月饼的库存量大小,收益值增加该种月饼的总售价大小。
- 2.如果该种月饼的库存量足够供应需求量,则只提供需求量大小的月饼,此时收益值增加当前需求量乘以该种月饼的单价,而需求量减为0.
- 这样,最后得到的收益值即为所求的最大收益值。
策略正确性的证明
:假设有两种单价不同的月饼,其单价分别为a和b(a<b)。如果当前需求量为K,那么两种月饼的总收入分别为aK与bK,而aK<bK显然成立,因此需要出售单价更高的月饼。
注意点
- 月饼库存量和总售价可以是浮点数(题目中只说是正数,没说是正整数),需要用double型存储。对于,总需求量D虽然题目说是正整数,但是为了后面计算方便,也需要定义为浮点型。很多得到“答案错误“的代码都错在这里。
- 当月饼库存量高于需求量时,不能先令需求量为0,然后再计算收益,这会导致该步收益为0。
- 当月饼库存量高于需求量时,要记得将循环中断,否则会出错。
AC
#include <stdio.h>
typedef struct{
double store; //库存量
double sell; //总售价
double price; //单价
}Moon;
int cmp( const void *a , const void *b ){ //按单价从高到低排序
Moon aa = *(Moon*)a;
Moon bb = *(Moon*)b;
return bb.price > aa.price;
}
int main(){
int i,N;
double D,sum=0;
Moon str[1010];
scanf("%d %lf",&N,&D);
for(i=0;i<N;i++){
scanf("%lf",&str[i].store); //读入库存量
}
for(i=0;i<N;i++){
scanf("%lf",&str[i].sell); //读入总售价
str[i].price = str[i].sell / str[i].store; //求出单价
}
qsort(str,N,sizeof(Moon),cmp); //按单价从高到低排序
for(i=0;i<N;i++){
if(str[i].store <=D){ //如果需求量高于月饼库存量
D -= str[i].store; //第i种月饼全卖出
sum += str[i].sell;
}else{
sum += str[i].price*D; //只卖出剩余需求量的月饼
break;
}
}
printf("%.2lf\n",sum);
return 0;
}
1023 组个最小数 (20分)
给定数字 0-9 各若干个。你可以以任意顺序排列这些数字,但必须全部使用。目标是使得最后得到的数尽可能小(注意 0 不能做首位)。例如:给定两个 0,两个 1,三个 5,一个 8,我们得到的最小的数就是 10015558。
现给定数字,请编写程序输出能够组成的最小的数。
输入格式:
输入在一行中给出 10 个非负整数,顺序表示我们拥有数字 0、数字 1、……数字 9 的个数。整数间用一个空格分隔。10 个数字的总个数不超过 50,且至少拥有 1 个非 0 的数字。
输出格式:
在一行中输出能够组成的最小的数。
输入样例:
2 2 0 0 0 3 0 0 1 0
输出样例:
10015558
原题链接
思考
- 用10个数字组成最小的数并输出,且 0 不能做首位。
- 先从19中选择个数不为0的最小的数输出,然后从09输出数字,每个数守输出次数为其剩余个数。
- 以样例为例,最高位为个数不为0的最小的数1,此后1的剩余个数减1(由2变为1)。
- 接着按剩余次数(0剩余两个,1剩余一个,5出现三个,8出现一个)依次输出所有数。
- 策略正确性的证明:
- 首先,由于所有数字都必须参与组合,因此最后结果的位数是确定的。
- 然后,由于最高位不能为0,因此需要从[1,9]中选择最小的数输出(如果存在两个长度相同的数的最高位不同,那么一定是最高位小的数更小)。
- 最后,针对除最高位外的所有位,也是从高位到低位优先选择[0,9]中还存在的最小的数输出
注意点
- 由于第一位不能是0,因此第一个数字必须从1~9中选择最小的存在的数字,
且找到这样的数字之后要及时中断循环。
AC
#include <stdio.h>
int main(){
int i,j,count[10]; //记录数字0~9的个数
for(i=0;i<10;i++){
scanf("%d",&count[i]);
}
for(i=1;i<10;i++){
if(count[i]>0){ //从1~9中选择count[i]中不为 0的最小的数
printf("%d",i);
count[i]--;
break; //找到一个后就中断
}
}
for(i=0;i<10;i++){ //从0~9中输出对应个数的数字
for(j=0;j<count[i];j++){
printf("%d",i);
}
}
return 0;
}
1027 打印沙漏 (20分)
本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印
*****
***
*
***
*****
所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。
输入格式:
输入在一行给出1个正整数N(≤1000)和一个符号,中间以空格分隔。
输出格式:
首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。
输入样例:
19 *
输出样例:
*****
***
*
***
*****
2
原题链接
思考
- 每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;
- 符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。
- 输出图像,输出剩下没用掉的符号数。
- 起初以常规思考先输出上部分,再输出下部分,但比较麻烦。
- 之后通过查询函数,可以通过以绝对值函数控制输出
- 通过公式 mm2-1 确定需要的层数
- 再通过公式 m-1-abs(m-1-i) 控制空格输出,2*abs(m-1-i)+1 控制符号输出
AC
#include <stdio.h>
#define abs(x) ((x) >= 0 ? (x):-(x))
int main(){
int N,i,j,m; //m为层数
char c;
scanf("%d %c",&N,&c);
for(m=1;m*m*2-1<=N;m++); //确定层数
m--;
for(i=0;i<2*m-1;i++){
for(j=0;j<m-1-abs(m-1-i);j++) //控制空格
putchar(' ');
for(j=0;j<2*abs(m-1-i)+1;j++) //控制符号
putchar(c);
printf("\n");
}
printf("%d",N-2*m*m+1);
return 0;
}