问题 C: 相聚HNUCM校园食堂
题目描述
HNUCM的食堂重新装修了,小明决定约上朋友去食堂相聚,在食堂里,小明看到了M位男同学,N位女同学,小明是一个颜值控,因此他对每一位男生和女生都有一个颜值打分,他心里yy着想为这些单身狗们进行配对,小明真是一个关心同学的人!但小明认为配对同学的颜值之差不能超过5,注意必须是一位男同学和一位女同学才能配对,虽然小明对于可以配对的人数已经有了答案,但他想考考你的编程能力,因此他想请你帮他用编程算一下最多可以配对多少个人。(本题介绍仅作题目背景使用,无任何其他观点)
输入
每个测试文件仅有一条测试数据。
第一行输入M,N,分别表示男同学的数量,女同学的数量。(1<=M<=100,1<=N<=100)
第二行输入M个正整数,分别表示男同学们的颜值。
第三行输入N个正整数,分别表示女同学们的颜值。
注意,所有人的颜值分数范围在[1,100]
输出
输出最多可以配对的总人数。
样例输入 Copy
5 4 10 65 23 67 80 5 15 60 90
样例输出 Copy
4
提示
样例中第一位男同学和第一位女同学配对,第二位男同学和第三位女同学配对。
输入两个整数 m 和 n,分别代表数组 a 和 b 的长度,之后在下面的两行中输入元素,以空格隔开,即可算出差值绝对值小于等于 5 的元素对数。
#include <stdio.h>
#include <stdlib.h>
const int N = 1005;
int a[1005]; // 数组 a
int b[1005]; // 数组 b
int cmp(const void* a, const void* b) {
return *(int*)a - *(int*)b;
}
int main() {
int m, n;
while (scanf("%d%d", &m, &n) != EOF) { // 循环读入两个数组的长度
for (int i = 0; i < m; i++) {
scanf("%d", &a[i]); // 读入数组 a
}
for (int i = 0; i < n; i++) {
scanf("%d", &b[i]); // 读入数组 b
}
qsort(a, m, sizeof(int), cmp); // 对数组 a 进行排序
qsort(b, n, sizeof(int), cmp); // 对数组 b 进行排序
int cnt = 0; // 存储差值绝对值小于等于 5 的元素对数
int i = 0, j = 0;
while (i < m && j < n) { // 双指针扫描 a 和 b 数组
if (abs(a[i] - b[j]) <= 5) { // 如果差值绝对值小于等于 5,则计数器加一,并将指针后移
cnt++;
i++;
j++;
}
else if (a[i] < b[j]) { // 如果 a[i] 比 b[j] 小,则将指针 i 后移
i++;
}
else if (a[i] > b[j]) { // 如果 a[i] 比 b[j] 大,则将指针 j 后移
j++;
}
}
printf("%d\n", cnt * 2); // 题目要求双向计算,因此结果要乘 2
}
return 0;
}
问题 D: ABC + DEF = GHI
题目描述
用1, 2, 3...9 这九个数字组成一个数学公式,满足:ABC + DEF = GHI,每个数字只能出现一次,编写程序输出所有的组合。
输入
无
输出
输出所有的 ABC + DEF = GHI,
每行一条数据,格式为ABC+DEF=GHI
输出结果按照ABC升序排列,如果ABC相同,则按照DEF升序排列。
#include <stdio.h>
#include <stdbool.h>
int s[9]; // 存储 9 个数的数组
bool b[9]; // 标记每个数是否已经被使用过的数组
void dfs(int istep); // 深度优先搜索函数
int main() {
for (int i = 0; i < 9; i++) {
s[i] = i + 1; // 初始化数组 s,存储数 1~9
b[i] = false; // 初始化数组 b,将所有数都标记为未使用
}
dfs(0); // 从第 0 步开始搜索
return 0;
}
void dfs(int istep) {
if (istep == 9) { // 如果搜索到第 9 步,则输出符合要求的三个数的和
if (s[0] * 100 + s[1] * 10 + s[2] + s[3] * 100 + s[4] * 10 + s[5] == s[6] * 100 + s[7] * 10 + s[8]) {
int x = s[0] * 100 + s[1] * 10 + s[2];
int y = s[3] * 100 + s[4] * 10 + s[5];
int z = s[6] * 100 + s[7] * 10 + s[8];
printf("%d+%d=%d\n", x, y, z); // 输出符合要求的三个数的和
}
}
for (int j = 1; j <= 9; j++) { // 枚举 1~9 的数字
if (!b[j - 1]) { // 如果数字未使用
s[istep] = j; // 将数字添加到结果数组中
b[j - 1] = true; // 标记数字已使用
dfs(istep + 1); // 继续搜索下一个步骤
b[j - 1] = false; // 回溯,将数字标记为未使用
}
}
}
问题 F: 马的遍历问题
题目描述
在5*4的棋盘中,马只能走斜“日”字。马从位置(x, y)处出发,把棋盘的每一格都走一次,且只走一次,请找出所有路径。
输入
x,y,表示马的初始位置。
输出
将每一格都走一次的路径总数,如果不存在该路径则输出“No solution!”。
样例输入 Copy
1 1 2 2
样例输出 Copy
32 No solution!
#include <stdio.h>
#include <stdbool.h>
int a[10][10]; // 存储棋盘
int k;
void slove(int x, int y, int step); // dfs 函数
bool check(int i, int j); // 判断是否可以到达一个位置
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) { // 循环读入输入
k = 0; // 存储匹配方案数,初始化为 0
for (int i = 1; i <= 5; i++) { // 初始化棋盘,将所有位置标记为未使用
for (int j = 1; j <= 4; j++) {
a[i][j] = 0;
}
}
slove(n, m, 1); // 从起始点开始 dfs
if (k == 0) { // 如果没有可行的路径,输出 No solution!
printf("No solution!\n");
}
else { // 输出可行的路径数
printf("%d\n", k);
}
}
return 0;
}
void slove(int x, int y, int step) {
if (step == 20) { // 如果搜索了 20 步,则找到了一组可行的路径
k++;
return;
}
int fx[] = { 1, 2, 2, 1, -1, -2, -2, -1 }; // 横向移动的步长
int fy[] = { 2, 1, -1, -2, -2, -1, 1, 2 }; // 纵向移动的步长
int dx, dy;
for (int i = 0; i <= 7; i++) { // 枚举 8 种移动方式
dx = x + fx[i];
dy = y + fy[i];
if (check(dx, dy)) { // 如果可以到达这个位置
a[x][y] = step; // 标记这个位置已经被使用
slove(dx, dy, step + 1); // 继续前往下一个位置
a[x][y] = 0; // 回溯,将这个位置标记为未使用
}
}
}
bool check(int i, int j) { // 判断一个位置是否可以到达
if (i >= 1 && i <= 5 && j >= 1 && j <= 4 && a[i][j] == 0) {
return true;
}
else {
return false;
}
}
问题 E: 油田问题
题目描述
输入一个m行n列的字符矩阵,统计字符“@”组成多少个八连块。如果两个字符“@”所在的格子相邻(横、竖或者对角线方向),即属于同一个八连块。
输入
输入行数m,以及列数n。
然后输入*和@
1<=n,m<=100
输出
样例输入 Copy
5 5 ****@ *@@*@ *@**@ @@@*@ @@**@
样例输出 Copy
2
#include <stdio.h>
void slove(int i, int j, int num, int n, int m, int index[100][100], char a[100][100]); // dfs 函数
int main() {
int m, n;
while (scanf("%d%d", &n, &m) != EOF && (n || m)) { // 循环读入输入 n 和 m,直到 n 和 m 都为 0
int k = 0; // 存储石油块的数量,初始化为 0
char a[100][100]; // 存储地图
int index[100][100]; // 标记地图上的每个点是否已经被检查过
for (int i = 0; i < n; i++) {
scanf("%s", a[i]); // 按行读入地图
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
index[i][j] = 0; // 初始化标记数组,将每个点标记为未检查
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == '@' && index[i][j] == 0) { // 如果这个点是石油块的一部分且未检查过
slove(i, j, ++k, n, m, index, a);
}
}
}
printf("%d\n", k);
}
return 0;
}
void slove(int i, int j, int num, int n, int m, int index[100][100], char a[100][100]) {
if (i < 0 || i >= n || j < 0 || j >= m)
return;
if (index[i][j] > 0 || a[i][j] != '@')
return;
index[i][j] = num;
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if ((x != 0 || y != 0) && (i + x >= 0 && i + x < n && j + y >= 0 && j + y < m))
slove(i + x, j + y, num, n, m, index, a);
}
}
}
问题 A: 又一道简单题
题目描述
输入一个四个数字组成的整数 n,你的任务是数一数有多少种方法,恰好修改一个数字,把它 变成一个完全平方数(不能把首位修改成 0)。比如 n=7844,有两种方法:3844=622 和 7744=882。
输入
输入第一行为整数 T (1<=T<=1000),即测试数据的组数,以后每行包含一个整数 n (1000<=n<=9999)。
输出
对于每组数据,输出恰好修改一个数字,把 n变成完全平方数的方案数
样例输入 Copy
2 7844 9121
样例输出 Copy
Case 1: 2 Case 2: 0
#include <stdio.h>
#include <math.h>
int main() {
int T, a, ans, i, j, b = 1, num, k;
scanf("%d", &T); // 读入测试数据组数
for (; T > 0; T--) { // 循环处理每组测试数据
scanf("%d", &a); // 读入测试数据
printf("Case %d: ", b++); // 输出当前处理的测试数据的编号
num = 0; // 存储符合条件的数的个数,初始化为 0
for (i = 1; i <= 4; i++) { // 枚举每个数位的数字
if (i == 1) j = 1;
else j = 0;
for (; j <= 9; j++) { // 枚举每个数字
if (i == 1) { // 处理千位数字
ans = j * 1000 + a % 1000;
if (j == a / 1000) continue; // 如果与原数相同,则跳过此次循环
}
else if (i == 2) { // 处理百位数字
if (j == a / 100 % 10) continue; // 如果与原数相同,则跳过此次循环
ans = j * 100 + a / 1000 * 1000 + a % 100;
}
else if (i == 3) {
if (j == a / 10 % 10) continue;
ans = j * 10 + a / 100 * 100 + a % 10;
}
else {
if (j == a % 10) continue;
ans = j + a / 10 * 10;
}
k = (int)sqrt(ans);
if (ans == k * k) num++;
}
}
printf("%d\n", num);
}
return 0;
}
问题 B: 自守数
题目描述
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:25^2 = 625,76^2 = 5776,9376^2 = 87909376。请求出n以内的自守数的个数。
输入
int型整数。
输出
n以内自守数的数量。
样例输入 Copy
2000
样例输出 Copy
8
#include <stdio.h>
#include <math.h>
int result = 0, index = -1, ar[50];
int digit(int n) {
for (int i = 1; ; i++) {
if (n / 10 == 0) {
return i;
}
else {
n /= 10;
}
}
}
int check(long long n) {
int len = digit(n);
long long tem = pow(10, len);
if (n * n % tem == n) {
return 1;
}
return 0;
}
int ar_check(int n) {
for (int i = 0; i <= index; i++) {
if (ar[i] == n) {
return 1;
}
}
return 0;
}
void dfs(int a, int n) {
if (a <= n) {
if (ar_check(a)) {
return;
}
else {
ar[++index] = a;
result++;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
int temp = digit(a);
int ta = pow(10, temp) * i + a;
int tta = pow(10, temp) * 10 * j + ta;
if (check(tta)) {
dfs(tta, n);
}
}
}
}
}
else {
return;
}
}
int main() {
int n, i;
scanf("%d", &n);
for (i = 0; i < 50; i++) {
ar[i] = -1;
}
dfs(0, n);
dfs(1, n);
dfs(5, n);
dfs(6, n);
printf("%d\n", result);
return 0;
}