Readme
本题解只提供了题目和题解代码,未提供讲解,后续会跟新B站视频详细讲解,大家可以关注等候。
B站:沐晨汐er_
链接:沐晨汐er_的个人空间-沐晨汐er_个人主页-哔哩哔哩视频 (bilibili.com)
A题 WA了20多发哈哈哈哈
题目
E
题目描述
现有n×n的棋盘,棋盘上每个格子只能放入黑白两种棋子中的一个,分别用字符'+'表示黑色棋子、'*'表示白色棋子、'0'表示未着子。
编写Judge函数,Judge函数原型如下:
int Judge(char **str, int n, char ch, struct solu *ps);
其中,形参str是指向棋盘的指针,形参n表示棋盘大小(n×n),形参ch('+'、'*'分别表示黑白棋子)表示棋子颜色,形参ps是指向保存连珠方法的结构体变量。
通过调用Judge函数,判断落子布局是否可以组成五子连珠,若可以则返回1,并将找到的第一个连珠方法保存在ps指向的结构体变量中;否则返回0。struct solu结构体的定义如下:
struct solu{
int x;
int y;
char direction;
};
其中,用x和y分别表示字符ch表示的棋子组成的第一个五子连珠的起始行号和起始列号(行号和列号均从0开始),用direction保存五子连珠的四种方向,可以在四种符号:'-','|','\','/'中取值,分别表示以x和y为起点,向右横向、向下竖向、向右下斜向、向左下斜向构成了五子连珠。
五子连珠寻找的优先级规则为:行优先(即先判断第0行的所有位置,然后是第1行、第2行……依次类推),方向优先级判断顺序为:向右横向、向下竖向、向右下斜向、向左下斜向。
输入:
+ 20
0+0++*0+*+++000++0++
0+00+0+*0+*00*00***0
+0+0000+++*0+**+*0**
+**+0++*0*+0**0*0**0
*00*++0*0*++00*+00*0
*+*0*++*00*+0+0+**+0
+*+++0+0000+0***+**+
00*0+*0**+*0*000**++
*+**000+0+***++**+++
*00+*+*+00++0***0*0*
+*0**++0++*0+****00*
*+**+++0++++*0000+++
+*+000*0**++*+**+0**
+*0****+000*++++0*0*
+**0*+*00+000*0**+0+
0**+**+***0*+**00+*0
*+0++***0000+*+++0**
+0**+0+++*+0++**+000
**++++**00++00*++0*+
00*000+00++00+0+*+00
说明:分别用字符'+'、'*'、'0'代表黑子、白子、未着子,第一行输入"+ 20"表示在20×20的棋盘上对黑子是否能够组成五子连珠进行判断。
输出:
1 1 \
说明:该结果表明第1行,第1列,有一个由'+'组成的向右下斜向的五子连珠方案,是满足条件的第一个解
代码
// E.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct solu
{
int x;
int y;
char direction;
};
int Judge(char **str, int n, char ch, struct solu *ps){
char t = '\0';
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
if (str[i][j] == ch){
if (j <= n-5 && str[i][j+1]==ch && str[i][j+2]==ch &&
str[i][j+3]==ch && str[i][j+4]==ch){
t = '-';
}else if (i <= n-5 && str[i+1][j]==ch && str[i+2][j]==ch &&
str[i+3][j]==ch && str[i+4][j]==ch){
t = '|';
}else if (i <= n-5 && j <= n-5 && str[i+1][j+1]==ch && str[i+2][j+2]==ch &&
str[i+3][j+3]==ch && str[i+4][j+4]==ch){
t = '\\';
}else if (i <= n-5 && j >= 4 && str[i+1][j-1]==ch && str[i+2][j-2]==ch &&
str[i+3][j-3]==ch && str[i+4][j-4]==ch){
t = '/';
}
}
if (t != '\0'){
ps->x = i;
ps->y = j;
ps->direction = t;
return 1;
}
}
}
return 0;
}
int main()
{
int n, i;
char ch;
struct solu s = {-1, -1, ' '};
scanf("%c%d", &ch, &n);
char *board[n];
for(i = 0; i < n; i++)
{
board[i] = (char *)malloc((n+1)*sizeof(char));
memset(board[i], 0, (n+1)*sizeof(char));
scanf("%s", board[i]);
}
if (Judge(board, n, ch, &s) == 1)
printf("%d %d %c\n", s.x, s.y, s.direction);
else
printf("0\n");
for(i = 0; i < n; i++)
{
free(board[i]);
}
return 0;
}
D
题目描述
给定一个有m个元素(m<50)的正整数整型数组nums和一个正整数k(0<k<20),现需要向nums数组中追加填充k个最小的未出现在数组nums中且互不相同的正整数,要求使填充后数组的各元素的累加和最小。请编写函数MinInsert()返回填充到nums中的k个整数之和。
函数原型:int MinInsert(int *pnums, int m, int k);
其中,形参pnums是指向nums整型数组的指针,形参m是数组元素的个数,形参k是要填充的正整数个数。
函数算法请参考下面的流程图。
注意:不能改变指定函数原型,仅需提交MinInsert()函数及其调用的自定义函数的实现代码。
示例 1:
输入:nums = {1,4,25,10,25}, k = 2
输出:5
解释:向数组中填充的两个互不相同且未出现的正整数是 2 和 3 。nums 最终元素和为 1 + 4 + 25 + 10 + 25 + 2 + 3 = 70 ,这是所有情况中的最小值。
所以填充到数组中的两个整数之和是 2 + 3 = 5 ,所以返回 5 。示例 2:
输入:nums = {5,6}, k = 6
输出:25
解释:向数组中填充的六个互不相同且未出现的正整数是 1 、2 、3 、4 、7 和 8 。nums 最终元素和为 5 + 6 + 1 + 2 + 3 + 4 + 7 + 8 = 36 ,这是所有情况中的最小值。
所以填充到数组中的六个整数之和是 1 + 2 + 3 + 4 + 7 + 8 = 25 ,所以返回 25 。
请参考下面的流程图编写代码。其中,gap是数组中的间隙。要循环判定数组的间隙大小,当间隙gap大于待填数量k时,依次填入整数;否则依次填满间隙,再调整待填数量k。最后如未达到要求的待填数量,则继续在尾部填充。
代码
// D.
#include <stdio.h>
int MinInsert(int *pnums, int m, int k){
int *t = pnums;
for (int i = 0; i < m; i++){
for (int j = 0; j < m; j++){
if (t[j] > t[i]){
int x = t[i];
t[i] = t[j];
t[j] = x;
}
}
}
int sum = 0, cnt = 0;
for (int i = 0; i < m; i++){
if (i == 0){
int cha = t[i] - 0;
if (cha > 1){
for (int j = 1; j < t[i]; j++){
sum += j;
cnt++;
if (cnt == k) return sum;
}
}
}else{
int cha = t[i] - t[i-1];
if (cha > 1){
for (int j = t[i-1]+1; j < t[i]; j++){
sum += j;
cnt++;
if (cnt == k) return sum;
}
}
}
}
if (cnt < k){
int x = t[m-1]+1;
while (cnt != k){
sum += x;
x++;
cnt++;
}
}
return sum;
}
int a[N] = {5,8,13};
void solve() {
cout << MinInsert(a,3,15) << endl;
}
signed main() {
int t = 1;
while(t--) {
solve();
}
return 0;
}
C
题目描述
假定有下面的结构体:
typedef struct {
unsigned int year; /* 有效年份 1900~2050 年*/
unsigned int month;
unsigned int day;
} Date, *PDate;
请实现下面的两个函数,其原型要求如下:
int ToDate(char *str, PDate pd);
int DaysCount(PDate sdate, PDate edate);
ToDate()函数将字符串str中的合法日期存入指针变量pd指向的结构体成员中,其中字符串str的基本形式为“YYYY-MM-DD”,YYYY代表年,MM代表月,DD代表日,如str为“2023-12-30”,则ToDate()函数的功能是将2023、12、30分别存入pd->year、pd->month、pd->day中。如果str中的日期数值范围或数据格式非法,函数返回-1,正常返回0。
DaysCount()函数计算两个日期sdate和edate之间差距是多少天,并返回计算结果。
输入:
2008-08-08
2023-12-30
输出:
5622
可以使用sscanf函数从字符串str中将年月日读取为整数,例如,sscanf(str, "%d-%d-%d", &year, &month, &day)。
另外,提供以下日期计算结果,供程序测试使用。
- 1949年10月01日开国大典,至今(2023年12月30日)已过27118天。
- 1950年10月25日抗美援朝,至今(2023年12月30日)已过26729天。
- 今天是2023年12月30日,距离西北农林科技大学90周年校庆(2024年09月10日),还有255天。
- 2023年09月11日开学,至今(2023年12月30日)已过110天。
代码
// C.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned int year;
unsigned int month;
unsigned int day;
} Date, *PDate;
int is_leap(int);
int month_days(int ,int);
int ToDate(char *str, PDate pd){
int year,month,day;
if ((sscanf(str, "%d-%d-%d", &year, &month, &day)) == 3){
if (year >= 1900 && year <= 2050 && month >= 1 && month <= 12 &&
day >= 1 && day <= 31){
pd->day = day;
pd->month = month;
pd->year = year;
return 0;
}
return -1;
}
return -1;
}
int DaysCount(PDate sdate, PDate edate){
int res = 0;
// 开始那年
int flag = is_leap(sdate->year);
res += month_days(sdate->month,flag) - sdate->day;
for (int i = sdate->month+1; i <= 12; i++){
res += month_days(i,flag);
}
// 后面的每一年
for (int i = sdate->year+1; i <= edate->year; i++){
res += is_leap(i) ? 366 : 365;
}
// 减去多加的
flag = is_leap(edate->year);
res -= month_days(edate->month,flag) - edate->day;
for (int i = edate->month+1; i<= 12; i++){
res -= month_days(i,flag);
}
return res;
}
int main()
{
char str1[12], str2[12];
Date sd, ed;
fgets(str1, 12, stdin);
fgets(str2, 12, stdin);
if (ToDate(str1, &sd) == 0 && ToDate(str2, &ed) == 0)
printf("%d\n", DaysCount(&sd, &ed));
else
printf("input data is invalid.\n");
return 0;
}
int is_leap(int year)
{
return ((year%4==0&&year%100!=0)||year%400==0);
}
int month_days(int month, int leap)
{
int m_days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if(month == 2)
return (leap == 1) ? 29 : 28;
else
return m_days[month];
}
B(?)
疑问
不懂为什么排序的算法,冒泡排序(稳定性算法)过85%,选择排序1.0过92%,最基础的选择排序2.0AC了。有大佬可以解释一下吗??
题目描述
从二进制文件“stud.dic”中读取指定范围内的学生数据,并使用结构体、文件操作、函数指针等实现对各科成绩的升、降序通用化排序。程序主体框架已完成,请仔细阅读已有代码,并完成下面的两个函数:
1.通用排序
函数原型为:void sort(stu *stud, int mode, int sub, int n);
其中,形参sub用于指定需要排序的科目,取值为0、1或2代表的科目编号,形参mode用于指定排序模式,1表示升序,2表示降序,从而实现对形参n指定的n个学生成绩进行排序,形参stud是需要参与排序学生的数组首地址指针。
2.从二进制文件读入指定数据
函数原型为:stu *read( FILE *fp, int m, int n);
其中,形参fp传入的是已打开二进制文件的文件指针,形参m用于指定范围的起始位置(从0开始编号), 形参n用于指定需要读取的学生数据个数。在函数内部,用动态内存分配存储空间,读入指定的数据到分配的空间后,返回其首地址。
注意:
- 在程序主体框架中,已给出了结构体、主函数、辅助函数类型定义以及所需要完成的函数原型。
- 不能改变程序主体框架和指定函数原型,仅需提交sort()和read()函数及其调用的自定义函数的实现代码。
- 在二进制文件中,学生信息最多为30条,且姓名中可能会有空格,如:“白 莹”,成绩中可能含有小数。
输入:
起始学生序号m,学生数量n,排序方式mode,排序科目编号sub
0 3 1 0
输出:
从第m个开始的n个学生信息,并以mode方式对科目sub排序
0th: 2009011360 卢 莹 13.27 85.45 26.72
1th: 2010036201 张 阳 87.10 54.00 63.90
2th: 2010036209 赵扶强 90.50 54.00 65.00
代码
// B.
#include <stdio.h>
#include <stdlib.h>
#define M 30
typedef struct STUDENT
{
int studentID;
char studentName[10];
float score[3];
} stu, *pstu;
typedef int (*CmpFunPtr)(float, float); /* 定义函数指针类型CmpFunPtr,该类型的指针指向的函数应该返回一个整型数据,且含有两个float型形参。 */
int compareA(float, float); /* 降序排序比较函数 */
int compareD(float, float); /* 升序排序比较函数 */
stu *read(FILE *fp, int m, int n);
void sort(stu *stud, int mode, int sub, int n);
void print(pstu stud, int n);
CmpFunPtr setmode(int mode); /* 返回一个CmpFunPtr类型的函数指针 */
int main()
{
struct STUDENT *stud;
FILE *fp;
int m, n, mode, sub;
scanf("%d%d%d%d",&m, &n, &mode, &sub);
if(m < 0 || m > M || n < 0 || n+m > M || (mode != 1 && mode != 2) || (sub != 0 && sub !=1 && sub != 2))
{
printf("error!\n");
exit(0);
}
fp = fopen("stud.dic", "rb");
if(fp == NULL )
exit(0);
stud=read(fp, m, n);
sort(stud, mode, sub, n);
print(stud, n);
free(stud);
fclose(fp);
return 0;
}
CmpFunPtr setmode(int mode)
{
if (mode == 1)
return compareD;
else
return compareA;
}
void print(pstu stud, int n)
{
int i;
for(i = 0; i < n; i++)
{
printf("%dth: %d %s %.2f %.2f %.2f\n", i, stud[i].studentID,
stud[i].studentName, stud[i].score[0], stud[i].score[1], stud[i].score[2]);
}
}
int compareA(float x, float y)
{
return x > y;
}
int compareD(float x, float y)
{
return x < y;
}
stu *read(FILE *fp, int m, int n)
{
stu *stud = (stu *)malloc(n * sizeof(stu));
if (stud == NULL)
{
exit(1);
}
fseek(fp, m * sizeof(stu), SEEK_SET);
fread(stud, sizeof(stu), n, fp);
return stud;
}
void sort(stu *stud, int mode, int sub, int n){
// 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法。
// 冒泡排序、插入排序、归并排序、基数排序是稳定的排序算法。
// //冒泡
// for (int i = 0; i < n; i++){
// for (int j = 0; j < n-1; j++){
// if (mode == 1){ // 升序
// if (stud[j].score[sub] > stud[j+1].score[sub]){
// stu temp = stud[j];
// stud[j] = stud[j+1];
// stud[j+1] = temp;
// }
// }else{ // 降序
// if (stud[j].score[sub] < stud[j+1].score[sub]){
// stu temp = stud[j];
// stud[j] = stud[j+1];
// stud[j+1] = temp;
// }
// }
// }
// }
// 选择 1.0
for (int i = 0; i < n - 1; i++){
for (int j = i+1; j < n; j++){
if (mode == 1){ // 升序
if (stud[j].score[sub] < stud[i].score[sub]){ // 比该位置小就换
stu temp = stud[i];
stud[i] = stud[j];
stud[j] = temp;
}
}else{ // 降序
if (stud[j].score[sub] > stud[i].score[sub]){
stu temp = stud[i];
stud[i] = stud[j];
stud[j] = temp;
}
}
}
}
// // 选择 2.0
// for (int i = 0; i < n - 1; i++){
// int idx = i;
// for (int j = i+1; j < n; j++){
// if (mode == 1){ // 升序
// if (stud[j].score[sub] < stud[idx].score[sub]){
// idx = j;
// }
// }else{ // 降序
// if (stud[j].score[sub] > stud[idx].score[sub]){
// idx = j;
// }
// }
// }
// stu temp = stud[i];
// stud[i] = stud[idx];
// stud[idx] = temp;
// }
}
A(过 90%)
疑问
不懂,说我越界了,求大佬指点,wa了20多发。。。。。。。。
题目描述
“行程长度编码(Run-Length Encoding,RLE)”是一种无损压缩编码方法,其核心思想是依次记录符号序列中的每个字符(忽略大小写)及其重复出现的次数。例如用户输入字符序列(字符串)AaABBBbCBB,则其RLE编码的结果为3A4B1C2B。
下面的代码实现对输入字符串的RLE编码,现要求在函数int rle(char *code, const char *seq);及 函数readSeq(char *seq, int n);定义中的五个空白处填充适当的表达式,完成程序功能。
其中:rle()函数形参seq为长度在(0, 80]间(strlen(seq)>0&&strlen(seq)≤80)的全部由大小写英文字母组成的字符串指针,形参code为RLE编码后的结果字符串指针。编码正常结束函数返回0;如字符串指针seq为空或字符串长度不合法时,不进行编码函数直接返回-1;当字符串seq中出现非英文字母的其他字符时,也不进行编码函数直接返回-2。
readSeq()从键盘读取最多n个字符到seq字符串中,以回车符或EOF字符为结束标志。
输入1:
KAAAEE
输出1:
1K3A2E
输入2:
aaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb
输出2:
10A10B10A10B10A10B10A10B
输入3:
abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefab
输出3:
1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B1C1D1E1F1A1B
代码
// A.
#include <stdio.h>
#include <string.h>
#define MAX_SEQ_LEN 80
int rle(char *code, const char *seq);
int readSeq(char *seq, int n);
int main()
{
char seq[MAX_SEQ_LEN + 1] = { 0 };
char code[2 * MAX_SEQ_LEN + 1];
int r;
readSeq(seq, MAX_SEQ_LEN);
r = rle(code, seq);
switch (r) {
case 0:
printf("%s\n", code);
break;
case -1:
printf("Length is inValid.\n");
break;
case -2:
printf("Has inValid character.\n");
break;
}
return 0;
}
/* 以上代码禁止提交 */
int readSeq(char *seq, int n)
{
int ch, k;
k = 0;
while ((ch = getchar())) {
if (ch == '\n' || ch == EOF || k == n) break; // if (__________(1)_________)
seq[k++] = ch;
}
seq[k] = '\0'; // _____(2)______;
return k;
}
int rle(char *code, const char *seq)
{
int i, len = 0;
if (strlen(seq) <= 0 || strlen(seq) > 80) return -1; // if (________(3)_______)
const char *p = seq; // p = seq;
// char *ptr = code;
// while (*p != '\0' && strlen(code) < strlen(seq)*2-1)
while (*p) { // while (____(4)____)
char token = *p;
i = 1;
token &= 0xDF;
if (token > 'Z' || token < 'A')
return -2;
while ((*(++p) == token || *(p) == token+32) && *p != '\0'){ // while (___(5)___)
i++;
}
// while (1){
// p++;
// if (*p == '\0') break;
// if (*p != token && *p != token+32) break;
// i++;
// }
len = sprintf(code, "%d%c", i, token);
code += len;
}
*code = '\0';
// code = ptr;
return 0;
}
// aaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbbaaaaaaaaaabbbbbbbbbb
// abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefab