PAT (Basic Level) Practice (中文)入门篇(4)C

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;
} 

star

发布了32 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/m0_46153949/article/details/104074675