2026 年 3 月 19 日
收获:
- 找分子分母的最大公约数可以从大到小依次来找能同时整除分子分母的数,相除则得到约分后的分数。
1. 双素数(Q593)
题目描述:
编写程序,显示从 3 起小于 100 的所有双素数(双素数:如果 p 和 q 都是素数且 q=p+2,则 p/q 称为双素数,例如 3/5,5/7 都是双素数)。
输出格式要求: "%4d/%d"
程序运行示例:
3/5 5/7 11/13 17/19 29/31 41/43 59/61 71/73
c
#include <stdio.h>
#include <math.h>
// 函数声明:判断素数
int prime(int n);
int main()
{
int n = 3;
// 遍历 3 到 100 的所有数字
while(n <= 100){
// 如果 n 和 n+2 都是素数,则是双素数
if(prime(n) && prime(n + 2)){
printf("%4d/%d", n, n + 2);
}
n++;
}
return 0;
}
// 判断素数的函数(优化的 6k±1 法)
int prime(int n){
if(n < 2) return 0; // 小于 2 不是素数
if(n == 2 || n == 3) return 1; // 2 和 3 是素数
if(n % 2 == 0 || n % 3 == 0) return 0; // 能被 2 或 3 整除不是素数
// 只需检查到 sqrt(n),且只检查 6k±1 形式的数
for(int i = 5; i <= sqrt(n); i += 6){
if(n % i == 0 || n % (i + 2) == 0) return 0;
}
return 1;
}
说明:
- 双素数对:(3,5), (5,7), (11,13), (17,19), (29,31), (41,43), (59,61), (71,73)
- 素数判断优化:只检查到√n,且跳过偶数和 3 的倍数
2. 组合数计算(Q567)
题目描述:
请编写函数 fuc(),函数的功能是:根据以下公式求出 p 的值,结果由函数值返回。m , n 是两个正整数,且 m>n。P= m!/(n!*(m-n)!)
输入格式要求: "%d %d" 提示信息:"请输入 m,n 的值 ( m>n ):\n"
输出格式要求: "n 项之和为:%lf\n"
程序运行示例:
请输入 m,n 的值 ( m>n ):
5 3
n 项之和为:10.000000
c
#include <stdio.h>
// 函数声明
double fuc(int m, int n);
int main()
{
int m, n;
printf("请输入 m,n 的值 ( m>n ):\n");
scanf("%d %d", &m, &n);
// 调用函数计算组合数
printf("n 项之和为:%lf\n", fuc(m, n));
return 0;
}
// 计算组合数 C(m,n) = m! / (n! * (m-n)!)
double fuc(int m, int n){
int i = m, j = n, k = m - n;
long mj = 1, nj = 1, mnj = 1; // 分别存储 m!, n!, (m-n)!
// 计算 m!
while(i > 0){
mj *= i;
i--;
}
// 计算 n!
while(j > 0){
nj *= j;
j--;
}
// 计算 (m-n)!
while(k > 0){
mnj *= k;
k--;
}
// 返回组合数
return mj * 1.0 / (nj * mnj);
}
说明:
- 这是组合数公式 C(m,n),表示从 m 个不同元素中取出 n 个元素的组合数
- 例如:C(5,3) = 5! / (3! × 2!) = 120 / (6 × 2) = 10
3. 分数约简(结构体)(Q6576)
题目描述:
假设有结构体定义如下:
c
struct fraction
{
int numerator; // 分子
int denominator; // 分母
};
编程对分数进行约减。
输入输出格式:
- 输入提示:
"please input a fraction,for example:16/24:" - 输入格式:
"%d/%d" - 输出格式:
"%d/%d\n"
程序运行示例:
please input a fraction,for example:16/24:4/6
2/3↙
c
#include <stdio.h>
// 定义分数结构体
struct fraction{
int numerator; // 分子
int denominator; // 分母
};
int main()
{
struct fraction f;
printf("please input a fraction,for example:16/24:");
scanf("%d/%d", &f.numerator, &f.denominator);
// 从大到小找最大公约数进行约分
for(int i = f.numerator - 1; i > 1; i--){
// 如果 i 能同时整除分子和分母
if(f.numerator % i == 0 && f.denominator % i == 0){
f.numerator /= i; // 分子除以 i
f.denominator /= i; // 分母除以 i
}
}
printf("%d/%d\n", f.numerator, f.denominator);
return 0;
}
说明:
- 通过从大到小遍历找到能同时整除分子和分母的最大数(即最大公约数)
- 然后分子分母同时除以这个数完成约分
- 例如:4/6 → 找到最大公约数 2 → 约分为 2/3
4. 八皇后问题(回溯算法)(Q428)
题目描述:
八皇后问题。在一个 8×8 的国际象棋棋盘上,有八个皇后,每个皇后占一格;要求皇后间不会出现相互"攻击"的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。问共有多少种不同的方法。
输入格式要求: 提示信息:"The possible configuration of 8 queens are:\n"
输出格式要求: " [%2d]:" "\n [%2d]:" " %d"
每三个结果输出为一行,每个结果中的第 i 个数据代表了第 i 行中皇后位置的列坐标
程序运行示例(部分):
The possible configuration of 8 queens are:↙
↙
[ 1]: 1 5 8 6 3 7 2 4 [ 2]: 1 6 8 3 7 4 2 5 [ 3]: 1 7 4 6 8 2 5 3↙
[ 4]: 1 7 5 8 2 4 6 3 [ 5]: 2 4 6 8 3 1 7 5 [ 6]: 2 5 7 1 3 8 6 4↙
...
[92]: 8 4 1 3 6 2 7 5
c
#include <stdio.h>
int board[8][8]; // 棋盘
int solution[100][8]; // 存储所有解
int count = 0; // 解的个数
// 判断在 (row, col) 位置放置皇后是否安全
int isSafe(int row, int col){
// 检查同一列
for(int i = 0; i < 8; i++){
if(board[i][col] == 1) return 0;
}
// 检查左上对角线
for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--){
if(board[i][j] == 1) return 0;
}
// 检查右上对角线
for(int i = row - 1, j = col + 1; i >= 0 && j < 8; i--, j++){
if(board[i][j] == 1) return 0;
}
return 1; // 安全
}
// 保存当前解
void saveSolution(){
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
if(board[i][j] == 1){
solution[count][i] = j + 1; // 记录第 i 行皇后的列号(从 1 开始)
}
}
}
}
// 递归求解八皇后问题
void solveQueens(int row){
int col;
// 如果已经放置了 8 个皇后,保存解
if(row == 8){
saveSolution();
count++;
return;
}
// 尝试在当前行的每一列放置皇后
for(col = 0; col < 8; col++){
if(isSafe(row, col)){ // 如果安全
board[row][col] = 1; // 放置皇后
solveQueens(row + 1); // 递归处理下一行
board[row][col] = 0; // 回溯,移除皇后
}
}
}
int main()
{
int i, j, k;
printf("The possible configuration of 8 queens are:\n");
// 初始化棋盘
for(i = 0; i < 8; i++){
for(j = 0; j < 8; j++){
board[i][j] = 0;
}
}
// 从第 0 行开始求解
solveQueens(0);
// 输出所有解(每行 3 个)
k = 0;
for(int i = 0; i < count; i++){
if(k % 3 == 0) printf("\n ");
printf(" [%2d]:", i + 1);
for(j = 0; j < 8; j++){
printf(" %d", solution[i][j]);
}
k++;
}
printf("\n");
return 0;
}
算法说明:
- 回溯法:逐行放置皇后,每放一个就检查是否安全
- 安全检查:同一列、两条对角线不能有其它皇后
- 解的表示:用一个长度为 8 的数组表示,第 i 个数字表示第 i 行皇后的列号
- 总共 92 种解法
5. 最大值最小值互换(指针参数)(Q1616)
题目描述:
按如下函数原型,编程实现计算数组 a 中 n 个整数的最大值和最小值,并互换它们在数组中的位置。
c
void MaxMinExchang(int a[], int n);
void Swap(int *x, int *y);
在主函数中调用函数 ReadData() 从键盘输入 10 个整数,调用函数 MaxMinExchang() 计算其最大值和最小值并互换它们在数组中的位置,最后调用函数 PrintData() 输出互换后的数组的各个元素值。
输入提示信息: "Input 10 numbers:"
输入格式: "%d"
输出提示信息: "Exchange results:"
输出格式: "%5d"
c
#include <stdio.h>
// 函数声明
void ReadData(int a[], int n);
void PrintData(int a[], int n);
void MaxMinExchang(int a[], int n);
void Swap(int *x, int *y);
int main()
{
int a[10];
printf("Input 10 numbers:");
ReadData(a, 10); // 输入数据
MaxMinExchang(a, 10); // 交换最大值和最小值
printf("Exchange results:");
PrintData(a, 10); // 输出结果
return 0;
}
/* 函数功能:输入数组 a 的 n 个元素值 */
void ReadData(int a[], int n)
{
int i;
for(i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
}
/* 函数功能:输出数组 a 的 n 个元素值 */
void PrintData(int a[], int n)
{
int i;
for(i = 0; i < n; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}
/* 函数功能:将数组 a 中的最大数与最小数位置互换 */
void MaxMinExchang(int a[], int n)
{
int maxValue = a[0], minValue = a[0], maxPos = 0, minPos = 0;
int i;
// 找出最大值和最小值及其位置
for(i = 1; i < n; i++)
{
if(a[i] > maxValue)
{
maxValue = a[i];
maxPos = i;
}
if(a[i] < minValue)
{
minValue = a[i];
minPos = i;
}
}
// 调用 Swap 函数交换最大值和最小值的位置
Swap(&a[minPos], &a[maxPos]);
}
/* 函数功能:两整数值互换 */
void Swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
说明:
- 使用指针参数实现两个数的交换
Swap(&a[minPos], &a[maxPos])传入的是地址,函数内部修改会影响原数组- 先遍历数组找到最大值和最小值的位置,然后交换