040.25-26计院网安院期末编程题
25-26 期末
点击 “原题描述” 即可品尝原味答辩
函数题
1 字符去重
原题描述

题目描述
- 给定一个字符串
str(长度大于 0 且小于 100),只包含小写字母"a—z"。 - 请你写一个函数把
str中重复的字符去掉。
函数接口定义
int deduplicate(char *str);
-
其中 str 是用户传入的参数,为指向待去重字符串的指针。
-
函数需返回删除字符的个数。
-
如果在 str 中某个字符出现了两次或两次以上,则只保留从前向后数第一个出现的字符,且保留下来的字符要保持原有顺序。
-
去重后的字符串仍保存在原来的数组中。
输入格式
只有一行,为一个长度大于 0 且小于 100 且只包含小写字母 "a—z" 的字符串
代表待去重字符串,测试用例保证合法
输出格式
共两行:
第一行为一个整数,为被删除字符的个数
第二行为一个字符串,为去重后的字符串
裁判测试程序样例
#include<stdio.h>
#define MAXLEN 100
int deduplicate(char *str);
int main()
{
char str[MAXLEN];
int count;
scanf("%s", str);
count = deduplicate(str);
printf("%d\n%s\n", count, str);
return 0;
}
/* 请在这里填写答案 */
输入样例
bupttpubuppttt
输出样例
10
bupt
- 代码限制: 16 KB
- 时间限制: 400 ms
- 内存限制: 64 MB
解法
int deduplicate(char *str){
int vis[26]={0};//标记是否出现过
int cnt=0;//统计删去字符的数量
char *i=str;//主指针,用于遍历str
char *j=str;//副指针,指向等待接收字符的位置,用于构建新str
while((*i) != '\0'){
char c=*i;
i++;
if(vis[c-'a']==0){//没有出现过
vis[c-'a']=1;//标记
*j = c;//接收第一次出现的字符
j++;
}
else{//删除字符
cnt++;
}
}
*j='\0';//添加结束符
return cnt;
}
2 黑杰克变种一
原题描述

题目描述
- 一种游戏,使用除大小王之外的52张牌,目标是使手中的牌的点数之和尽量大但不超过21
2~9按其 原点数 计算;K、Q、J、10都算作10点;A既可算作1点也可算作11点,由玩家自己决定。
A+9 -> 20 , A+4+8 -> 13 , A+3+A -> 15
- 增加新规则:
定义x为手牌中出现次数最多的花色的出现次数。若x大于3:总点数加5。若x等于3:总点数加2。
红桃J、红桃A、红桃K、梅花6 -> x = 3 -> 总点数加2
- 现请你写一段程序来计算手牌的总点数。
函数接口定义1
CARD * create(int n) ;
- 其中 n 是用户传入的参数,该函数创建一个长度为 n的CARD类型的动态数组。
函数接口定义2
int getPoints(CARD * deck , int size) ;
- deck 为指向存储一手牌的数组的指针。
- size 为数组中元素的个数。函数须返回这手牌的点数。
输入格式
-
共两行,第一行为一个整数n(1<n<10),代表这手牌的张数;
-
第二行是一个长度为
2×n字符串,代表n张牌。 -
每张牌都是由一个大写字母一个数字组成(大写字母在前)
-
大写字母代表花色(其中A代表黑桃、B代表红桃、C代表梅花、D代表方块)
-
数字代表牌面(其中1代表A牌,2到9依次代表2至9牌,K、Q、J和10牌均用0表示)
输出格式
- 只有一行,为一个整数,代表输入的这手牌的点数。
裁判测试程序样例
#include<stdio.h>
#include<stdlib.h>
#define SUITS 4 //花色数量
#define EXTRA_POINTS_2 5 //同色加分2
#define EXTRA_POINTS_1 2 //同色加分1
#define THRESHOLD_2 3 //加分门槛2
#define THRESHOLD_1 2 //加分门槛1
struct card
{
char face;
char suit;
};
typedef struct card CARD ;
CARD * create(int n) ;
int getPoints(CARD * deck , int size) ;
int main()
{
int i , n;
CARD *deck;
scanf("%d" , &n) ;
deck = create(n) ;
if ( deck == NULL )
return -1 ; //这里的return是因为没有获得内存而直接结束程序。
getchar();
for ( i = 0 ; i < n ; i++ )
scanf("%c%c" , &deck[i].suit , &deck[i].face) ;
printf("%d\n" , getPoints(deck , n)) ;
free(deck);
return 0;
}
/* 请在这里填写答案 */
输入样例
3
A1B3C1
输出样例
15
- 代码限制: 16 KB
- 时间限制: 400 ms
- 内存限制: 64 MB
解法
一个 A 的贡献至少为1,如果最后点数和小于21,尝试将一些A变成11
CARD * create(int n) {
CARD* arr= (CARD*)malloc(sizeof(CARD)*n);
return arr;
}
int getPoints(CARD * deck , int size){
int sum=0,cnt_A=0;
int cnt[4]={0};//统计4种花色出现次数
for(int i=0;i<size;++i){
char type=deck[i].suit;//花色
cnt[type-'A']++;
char val=deck[i].face;//面值
if(val=='1'){//注意这里是'1'而不是'A'
sum++;
cnt_A++;
}
else if(val=='0'){
sum+=10;
}
else sum+=val-'0';
}
int x=0;
for(int i=0;i<4;++i){
if(cnt[i]>x)x=cnt[i];
}
if(x>3)sum+=5;
if(x==3)sum+=2;
for(int i=cnt_A;i>=0;--i){
if(sum+10*i<=21){
sum+=10*i;
break;
}
}
return sum;
}
3 投票
原题描述

题目描述
- 班里共
n个同学,投票选班长 - 每个人可以投最多n张票、每张票只能选一个人,但不能把票投给重复的人;
- 每个同学投的票都有一个权值,这个权值就是该同学所获得的选票的张数;
一个人获得的票越多,他投出的票权重越高
- 某位同学的最终分数是所有给他投了票的同学的权值的和
- 现请你写一段程序来计算一下每位同学的最终分数。
函数接口定义1
void points(int *votes , int **students , int num);
- num是学生的总数;
- votes 是指向保存所有投票数据的一维int型数组的指针;
- students 指向一个一维int *型数组的指针。函数没有返回值。
- 函数的功能是将保存在votes所指向数组中的每位同学的信息的首地址保存到students所指向的指针数组中。
函数接口定义2
void count( int **students , int * ranks , int num);
- num是学生的总数;
- students 是指向保存每位同学的信息的首地址的指针数组的指针;
- ranks 是指向保存每位同学最终的分数数组的指针。函数没有返回值。
- 函数的功能是将每位同学的最终得分依据编号保存在ranks 所指向的一维int *型数组中。
输入格式
- 第一行为一个整数
n(1<n<=100),代表同学的总数;这些同学的编号为0到n-1。 - 后边
n行,每行代表一位同学获得的选票的情况; - 其中第1行代表0号同学的情况,第2行代表1号同学的情况……第n行代表n-1号同学的情况;
- 每行第一个整数
m代表该同学获得的选票的张数,后边m个整数为给他投票的同学的编号。
输出格式
- 共2×n行 ,每行一个整数
- 前n行依次为0到n-1号同学获得的票数,
- 后n行依次为0到n-1号同学的分数。
裁判测试程序样例
#include<stdio.h>
#define MAX_NUMBER 100 //学生的最多数量
void points(int *votes , int **students , int num);
void count( int **students , int * ranks , int num);
int main()
{
int num , numOfVotes , i , j , k = 0;
int *students[MAX_NUMBER]; //保存每个学生信息数组首地址的整型指针数组
int votes[MAX_NUMBER * (MAX_NUMBER + 1)]; //保存全部数据的整型数组
int ranks[MAX_NUMBER];// 保存每个学生的分数值的数组
//以下代码为输入数据的读入过程。
//其本质就是将所有num个同学的数据依次保存在一个一维数组votes中。
scanf("%d" , &num) ;
for (i = 0 ; i < num ; i++){
scanf("%d" , &numOfVotes) ; //读入每个学生获得的选票的张数
votes[k++] = numOfVotes;
for(j = 0 ; j < numOfVotes ; j++ , k++){
scanf("%d" , &votes[k]) ; //读入每个学生的具体投票人
}
}
points(votes , students , num);
for (i = 0 ; i < num ; i++) //依次输出每个学生获得的选票的张数
printf("%d\n" , students[i][0]) ;
//函数points执行过后,students中的指针应该指向每个同学的数据的首地址
//所以其第0个单元即为该同学获得的选票的张数
count(students , ranks , num);
for (i = 0 ; i < num ; i++) //依次输出每个学生的分数值
printf("%d\n" , ranks[i]) ;
return 0;
}
/* 请在这里填写答案 */
输入样例
5
5 0 1 2 3 4
4 1 2 3 4
2 0 1
3 2 3 4
3 1 2 3
输出样例
5
4
2
3
3
17
12
9
8
9
- 代码限制: 16 KB
- 时间限制: 400 ms
- 内存限制: 64 MB
解法
votes 是指向保存所有投票数据的一维int型数组的指针
对于样例,这个一维数组长这样
5 0 1 2 3 4 4 1 2 3 4 2 0 1 3 2 3 4 3 1 2 3
需要我们手动把它拆分,塞进对应的student[i]里
void points(int *votes , int **students , int num){
int* p=votes;
for(int i=0;i<num;++i){
int n=*p;//i学生收到的票数
students[i]=p;
p+=n+1;
}
}
void count( int **students , int * ranks , int num){
for(int i=0;i<num;++i){
int n=students[i][0];
ranks[i]=0;//初始化
for(int j=1;j<=n;++j){
int x=students[i][j];//x学生投票给了i学生
ranks[i]+=students[x][0];//x学生的票的权值
}
}
}
编程题
1 订单总价
原题描述

题目描述
- 买了
n种商品。告诉你每种商品的数量和单价。计算总价
输入格式:
- 共三行
- 第一行为一个整数
n(0<n<100),代表订单中共n种商品。 - 第二行与第三行均为
n个用空格分隔的正整数,其中第二行的正整数代表订单中每种商品的数量 - 第三行的正整数与第二行的正整数依次对应,代表每种商品的单价。
- 测试用例保证合法,且包括总价在内的所有整数均可以用int存储。
输出格式:
- 只有一行,为一个整数,代表订单总价。
输入样例:
5
5 5 9 1 30
1 5 8 7 10
输出样例:
409
- 代码长度限制 :16 KB
- 时间限制 :400 ms
- 内存限制 :64 MB
- 栈限制 :8192 KB
解法
#include<stdio.h>
int main(){
int n;
scanf("%d",&n);
int a[n];
for(int i=0;i<n;++i){
scanf("%d",a+i);
}
int b,ans=0;
for(int i=0;i<n;++i){
scanf("%d",&b);
ans+=a[i]*b;
}
printf("%d",ans);
}
2 最大池化
原题描述

题目描述
一个n阶方阵、n为偶数
用2×2的窗口对其进行压缩,压缩原则是保留窗口内的最大值
输入格式:
- 第一行为一个整数
n(为大于0且小于等于100的偶数),代表输入矩阵(一定为方阵)的阶。 - 后边是
n行,为n×n个整数矩阵,整数间均以一个空格分隔。测试用例保证合法,且所有整数均可以用int存储。
输出格式:
- 共2n行 ,每行 2n个数,每行的每个数均用一个空格分隔。
- 注意行末为换行符,没有空格。代表池化后的结果。
输入样例:
6
1 1 2 4 5 1
5 6 7 8 0 7
3 2 1 0 4 1
1 2 3 4 3 2
8 6 5 3 3 1
1 0 2 1 2 0
输出样例:
6 8 7
3 4 4
8 5 3
- 代码长度限制 :16 KB
- 时间限制 :400 ms
- 内存限制 :64 MB
- 栈限制 :8192 KB
解法
#include<stdio.h>
int main(){
int n;
scanf("%d",&n);
int m[n][n];
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
scanf("%d",&m[i][j]);
}
}
n/=2;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
int x=i*2,y=j*2;
int M=m[x][y];
if(m[x+1][y+1]>M)M=m[x+1][y+1];
if(m[x][y+1]>M)M=m[x][y+1];
if(m[x+1][y]>M)M=m[x+1][y];
printf("%d",M);
if(j!=n-1)printf(" ");
else printf("\n");
}
}
}
锐评一下函数题二、三
-
题干又臭又长不知所云,兜兜转转说不明白核心任务是什么
-
函数题二 :作为本题最特殊的一张牌
A,如果你完全忽视它
比如提交这份代码
int getPoints(CARD * deck , int size){
int sum=0,cnt_A=0;
int cnt[4]={0};
for(int i=0;i<size;++i){
char type=deck[i].suit;
cnt[type-'A']++;
char val=deck[i].face;
if(val=='0'){
sum+=10;
}
else sum+=val-'0';
}
int x=0;
for(int i=0;i<4;++i){
if(cnt[i]>x)x=cnt[i];
}
if(x>3)sum+=5;
if(x==3)sum+=2;
return sum;
}
居然可以得到70大分 !
如果你把判断条件val=='1'写成val=='A'
看到70这个分数真的很难想象到是题读错了,不过这是后话
核心问题还是测试数据太太太弱了 !
- 函数题三:意义不明
考察指针——为了这蝶醋包的饺子
能一边读懂这道题想让你干什么的选手高考阅读理解应该可以拿满分
如果一道函数题居然需要根据主函数猜测传参的含义,函数的功能
那不如直接出成编程题吧

浙公网安备 33010602011771号