前言
有一说一,用C语言刷题并不是一件很令人愉快的事。
拿代码实现很难,相关的题解也很少,即使找到了题解,也很容易是错误的。
但因为我自己想走的大方向是偏向底层的物联网,再加上我的python和C++还没学完,因此拿C语言修炼内功就变成了刚需
不过我依旧认为C语言很重要,是其他一切语言的基础。
目前我快要学完python了,过两天开始用python和C++刷题后,我也会时不时的回归一下C语言。
提示:
第九题我只研究出了使部分测试点通过的代码,有会的大神可以在评论区中把代码亮出来,欢迎一起讨论
1001:
对给定的任一不超过 1000 的正整数?n,简单地数一下,需要多少步(砍几下)才能得到?n=1?
#include <stdio.h>
int main()
{
int n, count = 0;
scanf("%d", &n);
while (n != 1)
{
switch (n % 2)
{
case 0:
n = n / 2;
count++;
break;
case 1:
n = (3 * n + 1) / 2;
count++;
break;
default:
break;
}
}
printf("%d", count);
return 0;
}
求2的余数,三种情况在switch....case语句中进行分别讨论
讨论的情形可以通过读题得知:?对任何一个正整数?n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把?(3n+1)?砍掉一半。这样一直反复砍下去,最后一定在某一步得到?n=1。
把这句话转化为数学公式即可
1002:
读入一个正整数?n,计算其各位数字之和,用汉语拼音写出和的每一位数字
这道题可以用switch..case语句列出汉语拼音的每种读法,不过。。有些不太美观。
我用的是二维数组的方法,可以看程序中的注释
#include <stdio.h>
#include <stdlib.h>//储存排序和查找程序的头文件
#include <string.h>
int main() {
char num[102];
int put[20];
int sum = 0, i = 0, lenth = 0, k = 0;
char pin[10][5] = { "ling","yi","er","san","si","wu","liu","qi","ba","jiu" };//用二维数组的第一维储存汉语拼音
scanf("%s", &num);//把字符串按照字符形式存储到num数组中
while (num[i] != '\0') {
sum += num[i++] - '0';//把字符形式的数字依次相加
}
while (sum > 0) {
put[k++] = sum % 10;//这段程序是为了把数字转化为三位数
sum = sum / 10;
lenth++;//计算汉语拼音一共需要打印的长度
}
for (i = lenth - 1; i >= 0; i--) {//数组从0开始计数
printf("%s", pin[put[i]]);//用二维数组的第二维储存put[k++]
if (i != 0) {
printf(" ");//顺便加上空格,以免格式错误
}
}
return 0;
}
还有,不要把多维数组妖魔化
比如说二维数组,其实就是一维数组的一维数组 ,数组套数组。
1003:
答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案错误”。
得到“答案正确”的条件是:
- 字符串中必须仅有?
P 、?A 、?T 这三种字符,不可以包含其它字符; - 任意形如?
xPATx ?的字符串都可以获得“答案正确”,其中?x ?或者是空字符串,或者是仅由字母?A ?组成的字符串; - 如果?
aPbTc ?是正确的,那么?aPbATca ?也是正确的,其中?a 、?b 、?c ?均或者是空字符串,或者是仅由字母?A ?组成的字符串。
现在就请你为 PAT 写一个自动裁判程序,判定哪些字符串是可以获得“答案正确”的。
这道题主要考的就是找规律,规律一和规律二是规律三的子集。
AAPAATAAA是正确的,但是AAAPAATAA就不对了,也就是说,
前面的字符串必须比后面的字符串少一个A;
中间的A个数乘以开始的字符串个数=后面的字符串个数。
因此可以依据P,T,A三个字母进行字符串的分割,用二维数组,第一维存储字符个数,第二维存储字符,并进行条件判断。例如有一个A应该怎么做,依次类推。
代码如下:
#include<stdio.h>
#include<string.h>
int main()
{
int n;
scanf("%d", &n);
getchar();
char recode[n][200];
int i, j;
for (i = 0; i < n; i++)
{
scanf("%s", recode[i]);
getchar();
}
for (i = 0; i < n; i++)
{
int flagt = 0, flagp = 0, flaga = 0, flag = 0;
int nump = 0, numt = 0, num = 0;
for (j = 0; flag == 0 && recode[i][j] != '\0'; j++)
{
if (recode[i][j] != 'P' && recode[i][j] != 'A' && recode[i][j] != 'T')
{
flag = 1;
break;
}
else if (recode[i][j] == 'P')
{
flagp++;
}
else if (recode[i][j] == 'T')
{
flagt++;
}
else if (flagp > 1 || flagt > 1)
{
flag = 1;
break;
}
else if (flagp == 0 && flagt == 0 && recode[i][j] == 'A')
{
nump++;
}
else if (flagp != 0 && flagt == 0 && recode[i][j] == 'A')
{
numt++;
}
if (recode[i][j] == 'A')
{
num++;
}
}
if (flag != 0 || num == 0 || flagp == 0 || flagt == 0)
{
printf("NO\n");
}
else if (nump * numt == (num - nump - numt))
{
printf("YES\n");
}
else printf("NO\n");
}
return 0;
}
1004:
读入?n(>0)名学生的姓名、学号、成绩,分别输出成绩最高和成绩最低学生的姓名和学号
这道题可以题用结构体储存学生的信息,表示出成绩后进行大小比较。
其实看似复杂的题,都是用一个个简单程序叠加起来的,我们需要的是化繁为简的能力,以及。。。一定的数学基础,能自己尝试写代码的勇气,还有一遍遍查找bug的毅力。
#include <stdio.h>
#include <stdlib.h>
struct student {
char name[11];
char id[11];
int score;
}temp, ans_max, ans_min;
int main()
{
int n;
ans_min.score = 101, ans_max.score = -1;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%s%s%d", &temp.name, &temp.id, &temp.score);
if (temp.score < ans_min.score) {
ans_min = temp;
}
if(temp.score>ans_max.score){
ans_max = temp;
}
}
printf("%s %s\n", ans_max.name, ans_max.id);
printf("%s %s\n", ans_min.name, ans_min.id);
return 0;
}
(其实这道题用python很好做,可惜我当时不太会)
1005:
现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。
?这道题写起来稍微有点绕,不过思路很清晰
输入元素遍历一遍,求猜想数时遍历一遍,判断关键数字时倒着再来一遍
#include <stdio.h>
int main()
{
int K = 0, n = 0;
int tabel[101] = { 0 };
scanf("%d", &K);
//将元素对应位置标记为1
for (int i = 0; i < K; i++)
{
scanf("%d", &n);
tabel[n] = 1;
}
//遍历数组,求还存在数的猜想数
for (int i = 1; i <= 100; i++)
{
if (tabel[i])
{
for (n = i; n > 1; )
{
if (n % 2)
{
n = (3 * n + 1) / 2;
}
else
{
n /= 2;
}
//检验猜想数是否存在,需考虑猜想数超出100,数组越界的问题
if (n <= 100 && tabel[n])
{
tabel[n] = 0;
K--;
}
}
}
}
for (int i = 100; i >= 1; i--)
{
if (tabel[i] == 1)
{
printf("%d%c", i, --K ? ' ' : '\0');
}
}
return 0;
}
1006:
让我们用字母?B ?来表示“百”、字母?S ?表示“十”,用?12...n ?来表示不为零的个位数字?n (<10),换个格式来输出任一个不超过 3 位的正整数。例如?234 ?应该被输出为?BBSSS1234 ,因为它有 2 个“百”、3 个“十”、以及个位的 4。
这道题比较简单,把C语言基础题:如何表示一个三位数弄会就行,然后用for循环输出字符和数字
如没有编译出来,可以看我C语言专栏里的前几篇文章,进行一下基础的回顾
#include <stdio.h>
int main()
{
int b=0, s=0, n=0, B,S,number,i;
scanf("%d", &number);
b=number/100;
s = number / 10 % 10;
n= number%10;
for (i = 1; i <= b; i++)
{
printf("B");
}
for (i = 1; i <= s; i++)
{
printf("S");
}
for (i = 1; i <= n; i++)
{
printf("%d",i);
}
printf("\n");
return 0;
}
1007:?
让我们定义dn?为:dn?=pn+1??pn?,其中pi?是第i个素数。显然有d1?=1,且对于n>1有dn?是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。
现给定任意正整数N (<105),请计算不超过N 的满足猜想的素数对的个数。
?这又是一道比较难的题,我当时做的时候做成了素数,后来才发现差的很远,这道题卡了我好几天。
#include<stdio.h>
#include<math.h>
int main()
{
int i, j, k, temp, n = 0;
int s = 2;
scanf("%d", &k);
if (k == 1) return 0;
else
for (i = 2; i <= k; i++)
{
temp = sqrt(i);
for (j = 2; j <= temp; ++j)
if (i % j == 0) break;
if (j >= temp + 1)
{
if ((i - s) == 2)
n++;
s = i;
}
}
printf("%d", n);
return 0;
}
附一下我当时写的注释:
//一定要写返回值!此题用数组!
//这样才是正确的!!!int p[100];int p[100]=0是错的!!!
//它不是在求素数,是在求除过之后是素数的数!!!!!
//你得先判断是不是素数,然后判断相邻的两个素数是否相差2!!
?这是我当时写的运行部分正确的代码:
#include <stdio.h>
int main()
{
int N, i,j,m=0,h=0;
int prime;
int p[1000];
scanf("%d", &N);
for (i = 2; i < N; i++) {
prime = 1;
for (j = 2; j < i; j++)
{
if (i % j == 0)
{
prime = 0;
break;
}
}
if(prime)
{
p[m] = i;
if (m>=1&&p[m] - p[m-1] == 2)
h++;
m++;
}
}
printf("%d", h);
return 0;
}
1008:
一个数组A中存有N(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥0)个位置,即将A中的数据由(A0?A1??AN?1?)变换为(AN?M??AN?1?A0?A1??AN?M?1?)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法??
?可以先输出5,6,后输出1,2,3,4,注意把循环的位数数准了就可以
#include <stdio.h>
int main()
{
int m, n, a[1000], i;
int count = 0;
scanf("%d %d", &m, &n);//是格式问题!!!!
for (i = 0; i < m; i++)
scanf("%d", &a[i]);
n = n % m;//计算需要右移的位数
for (i = m - n; i < m; i++) {
printf("%d", a[i]);//输出m-n到m-1号
count++;
if (count < m)
printf(" ");//如果已经输出的个数小于m,则要输出空格
}
for (i = 0; i < m - n; i++) {
printf("%d", a[i]);
count++;
if (count < m)
printf(" ");
}
return 0;
}
另一种方式使用队列(先进先出)来实现,这对C语言不太友好,毕竟队列还要自己写
#define MAX 102
#include <stdio.h>
int Divisor(int x, int y) {
if (!(y % x))
return x;
return Divisor(y % x, x);
}
int main() {
int a[MAX] = { 0 };
int num, step;
scanf("%d %d", &num, &step);
for (int i = 1; i <= num; i++) {
scanf("%d", &a[i]);
}
step = step % num;
int loop = Divisor(num, step);
for (int i = 1; i <= loop; i++) {
int temp = i, p;
int last_p = a[temp];
do {
temp = (temp + step) % num;
if (!temp)
temp = num;
p = a[temp]; //取出下一个
a[temp] = last_p; //存入上一个
last_p = p;
} while (temp != i);
}
for (int i = 1; i <= num - 1; i++) {
printf("%d ", a[i]);
}
printf("%d\n", a[num]);
return 0;
}
1009:
给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出。
这个不知道为什么,不是部分正确就是编译错误,我自己也很懵
部分正确的代码:
#include <stdio.h>
#include <string.h>
int main()
{
char str[100];
scanf("%s", str);
int len = strlen(str), r = 0, h = 0, i;
char ans[100][100];
for (i = 0; i < len; i++) {
if (str[i] != ' ')
ans[r][h++] = str[i];
else {
ans[r][h] = '\0';
r++;
h = 0;
}
}
for (i = r; i >= 0; i--) {
printf("%s", ans[i]);
if (i > 0)
printf(" ");
}
return 0;
}
编译错误的代码:
#include <stdio.h>
#include <string.h>
int gaibian(char* str, int ans[100][100])
{
int len = strlen(str), r = 0, h = 0, i;
for (i = 0; i < len; i++) {
if (str[i] != ' ')
ans[r][h++] = str[i];
else {
ans[r][h] = '\0';
r++;
h = 0;
}
}
}
int main()
{
char* str;
int ans[100][100];
scanf("%s", str);
int len = strlen(str), r = 0, h = 0, i;
for (i = r; i >= 0; i--) {
gaibian(*str, ans[100][100])
printf("%s", ans[i]);
if (i > 0)
printf(" ");
}
return 0;
}
欢迎大家的讨论,批评,指正。?
|