三角形分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio.h>
#include <math.h>

// 函数 sort:用于对三个数 a, b, c 进行排序,使它们按从小到大的顺序排列
//只需要知道,这个函数会将我们输入的三个数字 从小到大排序
void sort(int *x, int *y, int *z)
{
// 如果 x 比 y 大,则交换 x 和 y 的值
if (*x > *y) {
int temp = *x; // 临时保存 x 的值
*x = *y; // 将 y 的值赋给 x
*y = temp; // 将原来的 x 的值赋给 y
}
// 如果 x 比 z 大,则交换 x 和 z 的值
if (*x > *z) {
int temp = *x; // 临时保存 x 的值
*x = *z; // 将 z 的值赋给 x
*z = temp; // 将原来的 x 的值赋给 z
}
// 如果 y 比 z 大,则交换 y 和 z 的值
if (*y > *z) {
int temp = *y; // 临时保存 y 的值
*y = *z; // 将 z 的值赋给 y
*z = temp; // 将原来的 y 的值赋给 z
}
}

// 函数功能:用于对三角形进行分类
// 参数 a, b, c 表示三角形的三条边
//只需要知道,这个函数是判断三角型类型的,判断原理就是 三角形的三边关系
void classify_triangle(int a, int b, int c)
{
sort(&a, &b, &c); // 调用 sort 函数对 a, b, c 进行排序,使 a <= b <= c

// 检查是否能构成三角形(两边之和必须大于第三边)
if (a + b <= c)
{
printf("Not triangle\n"); // 如果不能构成三角形,输出 "Not triangle"
return; // 直接结束函数
}

// 如果三条边相等,则是等边三角形(等边三角形也是锐角三角形和等腰三角形)
if (a == b && b == c)
{
printf("Acute triangle\n"); // 等边三角形是锐角三角形
printf("Isosceles triangle\n"); // 也是等腰三角形
printf("Equilateral triangle\n"); // 是等边三角形
return; // 直接结束函数
}

// 计算每条边的平方,方便后面判断三角形类型
int a2 = a * a, b2 = b * b, c2 = c * c;

// 判断是否是直角三角形:a^2 + b^2 == c^2
if (a2 + b2 == c2)
{
printf("Right triangle\n"); // 输出 "Right triangle"
}
// 判断是否是锐角三角形:a^2 + b^2 > c^2
else if (a2 + b2 > c2)
{
printf("Acute triangle\n"); // 输出 "Acute triangle"
}
// 剩下的情况就是钝角三角形:a^2 + b^2 < c^2
else
{
printf("Obtuse triangle\n"); // 输出 "Obtuse triangle"
}

// 如果有两条边相等,则是等腰三角形
if (a == b || b == c || a == c) {
printf("Isosceles triangle\n"); // 输出 "Isosceles triangle"
}
}

int main()
{
int a, b, c;
// 从用户输入中读取三条边的长度
scanf("%d %d %d", &a, &b, &c);
// 调用 classify_triangle 函数来分类三角形
classify_triangle(a, b, c);
return 0;
}

sort 函数确保三条边按照从小到大的顺序排列,便于后续分类。

classify_triangle 通过对三边长度的平方计算来判断是直角、锐角、钝角三角形,同时还会判断是否是等腰或等边三角形

质数口袋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>

// 函数功能:用于判断一个数是否为质数
// 参数 n:要判断的整数
// 只需要知道,这个函数是判断是否为质数的,返回 1 表示是质数,0 表示不是质数
int is_prime_num(int n)
{
if (n <= 1) return 0; // 1 和小于 1 的数都不是质数
if (n == 2) return 1; // 2 是质数,直接返回 1
if (n % 2 == 0) return 0; // 偶数除了 2 以外都不是质数,直接返回 0

// 遍历所有奇数从 3 到 sqrt(n),检查 n 是否能被这些数整除
for (int i = 3; i * i <= n; i += 2)
{
// 如果 n 能被某个奇数整除,则不是质数,返回 0
if (n % i == 0) return 0;
}
// 如果循环结束,没有发现任何整除因子,则 n 是质数,返回 1
return 1;
}

int main()
{
int L; // 存储用户输入的上限 L
scanf("%d", &L); // 从用户输入中读取 L 的值
int sum = 0, count = 0; // 初始化两个变量:sum 用于存储质数的和,count 记录质数的个数

// 从 2 开始逐个检查质数,直到质数的和超过 L
for (int i = 2; sum + i <= L; i++) // 注意sum + i不会进行赋值,只会进行判断,如果加上下一个数字超出了L,那么循环就执行完毕
{
// 检查 i 是否为质数
if (is_prime_num(i))
{
sum += i; // 将质数 i 加到 sum 中
printf("%d\n", i); // 输出当前找到的质数
count++; // 质数计数器加 1
}
}

// 输出总共找到的质数个数
printf("%d\n", count);
return 0;
}

质数判断函数 is_prime_num

  • 对于输入的整数 n,首先排除掉所有小于等于1的数(它们都不是质数)。
  • 直接判断2是否是质数(2是唯一的偶数质数)。
  • 对于大于2的偶数,直接返回0(它们都不是质数)。
  • 然后,只需检查奇数因子是否能整除 n,因为偶数已经被排除。检查的范围是从3到 sqrt(n),因为如果 n 能被大于 sqrt(n) 的数整除,必然也能被某个小于 sqrt(n) 的数整除。

主函数 main

  • 用户输入一个整数 L,表示质数和的上限。
  • 程序从2开始寻找质数,依次调用 is_prime_num 函数,找出质数并计算它们的和。
  • 当质数的和加上下一个质数超过 L 时,停止寻找,并输出找到的所有质数及质数的总数量。

存储计划

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>

int main() {
int budget[12], money = 0, savings = 0, month_income = 300, first_fail_month = -1, i;

// 读取用户输入的每个月的开销
for (i = 0; i < 12; i++)
{
scanf("%d", &budget[i]); // 读取第 i 个月的预算(开销)
}

// 模拟 12 个月的收入与开销
// 模拟的原理:
// 每次新增300元,判断扣除开销后的数字,当第一个无法开销的月份出现(之所以+1是因为索引是从0开始的),跳出本次循环,继续向后
// 每次 将 整钱存入,即:有325元,则存入300,而留下25,这25将计入下个月的开销,开销后再统计 存入的 + 零钱
// 第一个无法开销的月份初始化为-1,只要没有被重新赋值,那么说明所有月份都可以正常开销
for (i = 0; i < 12; i++)
{
// 每月收入 300 元
money += month_income;

// 扣除每月的开销
money -= budget[i];

// 检查剩余的钱是否小于 0(即当前月的收入不足以支付预算)
if (money < 0)
{
first_fail_month = i + 1; // 记录第一个无法支付开销的月份(用 1 基数)
break; // 结束循环,不再继续处理后面的月份
}

// 将每月多余的部分(100 元的倍数)存起来
savings += (money / 100) * 100; // 把多余的部分按 100 的倍数存入储蓄
money %= 100; // 只保留不满 100 的零钱
}

// 如果有一个月无法支付开销
if (first_fail_month != -1)
{
printf("-%d\n", first_fail_month); // 输出第一个无法支付开销的月份,前面加负号
}
// 否则,所有月份的开销都能支付
else
{
// 将所有储蓄乘以 1.2(相当于加上 20% 的利息),并加上剩下的零钱
savings = savings * 1.2 + money;
printf("%d\n", savings); // 输出最终的总储蓄
}

return 0;
}

变量介绍:

  • budget[12]:存储每个月的开销。
  • money:当前手头的钱,初始为 0,每月会增加 300 元的收入并扣除相应的开销。
  • savings:用于记录每个月能储存的金额,按 100 的倍数储存,剩下的零钱不会存入。
  • month_income:每月收入 300 元。
  • first_fail_month:记录第一个无法支付预算的月份,初始值为 -1(表示能支付所有月份的预算)。

程序逻辑:

  • 第一个 for 循环从用户输入中读取每个月的开销数据。
  • 第二个 for 循环模拟每个月的收入和开销,并计算储蓄情况。如果某个月无法支付预算,记录该月份并立即停止循环。
  • 如果所有月份的开销都能支付,计算总储蓄(包括剩余的钱)并输出结果。否则,输出第一个无法支付的月份,并在前面加上负号

校门口的树

题目

某校大门外长度为 ll 的马路上有一排树,每两棵相邻的树之间的间隔都是 11 米。我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 ll 的位置;数轴上的每个整数点,即 0,1,2,…,l0,1,2,…,l,都种有一棵树。

由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入格式

第一行有两个整数,分别表示马路的长度 ll 和区域的数目 mm

接下来 mm 行,每行两个整数 u,vu,v,表示一个区域的起始点和终止点的坐标。

输出格式

输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h> 

#define MAX_LENGTH 10001 // 定义数组的最大长度为 10001,确保能存放足够多的树的信息

int main() {
int l, m; // l 表示路的长度(从 0 到 l 共 l+1 米),m 表示需要砍树的区间数量
int trees[MAX_LENGTH] = {0}; // 定义一个数组来表示每米是否有树,初始化为 0
int u, v, remaining_trees = 0; // u 和 v 表示每次要砍掉树的区间,remaining_trees 记录剩余的树的数量
int i, j; // 循环变量

// 读取路的长度 l 和砍树区间的数量 m
scanf("%d %d", &l, &m);

// 初始化所有的位置为 1,表示每米上都有树
for (i = 0; i <= l; i++) {
trees[i] = 1; // 1 表示这米有树
}

// 循环读取每个需要砍树的区间 [u, v]
for (i = 0; i < m; i++) {
scanf("%d %d", &u, &v); // 读取砍树的起点 u 和终点 v
// 将区间 [u, v] 中的树标记为 0,表示这些树被砍掉
for (j = u; j <= v; j++) {
trees[j] = 0; // 0 表示该米的树被砍掉
}
}

// 遍历所有位置,计算还剩多少棵树
for (i = 0; i <= l; i++) {
if (trees[i] == 1) { // 如果该位置的树没有被砍掉
remaining_trees++; // 剩余树的数量加 1
}
}

// 输出剩余的树的数量
printf("%d\n", remaining_trees);

return 0;
}

初始化阶段:

  • trees[MAX_LENGTH] = {0}:定义一个数组 trees,长度为 MAX_LENGTH。每个元素代表一个位置的树是否存在,1 表示有树,0 表示树被砍掉。
  • 初始时,所有位置的树都标记为 1(即有树)。

砍树的过程:

  • 每次输入一个区间 [u, v],程序会将这个区间内的树都标记为 0,表示树被砍掉。

统计剩余树的数量:

  • 遍历整个数组 trees,计算哪些位置的值仍然是 1,这就表示树还在,记录并输出剩余的树的数量。

MC插火把

题目

话说有一天 linyorson 在“我的世界”开了一个 n×nn×n 的方阵,现在他有 mm 个火把和 kk 个萤石,分别放在 (x1,y1)∼(xm,ym)(x1,y1)∼(x**m,y**m) 和 (o1,p1)∼(ok,pk)(o1,p1)∼(o**k,p**k) 的位置,没有光并且没放东西的地方会生成怪物。请问在这个方阵中有几个点会生成怪物?

P.S. 火把的照亮范围是:

1
2
3
4
5
|暗|暗| 光 |暗|暗|
|暗|光| 光 |光|暗|
|光|光|火把|光|光|
|暗|光| 光 |光|暗|
|暗|暗| 光 |暗|暗|

萤石:

1
2
3
4
5
|光|光| 光 |光|光|
|光|光| 光 |光|光|
|光|光|萤石|光|光|
|光|光| 光 |光|光|
|光|光| 光 |光|光|

输入格式

输入共 m+k+1m+k+1 行。
第一行为 n,m,kn,m,k
第 2 到第 m+1m+1 行分别是火把的位置 xi,yix**i,y**i
第 m+2m+2 到第 m+k+1m+k+1 行分别是萤石的位置 oi,pio**i,p**i

注:可能没有萤石,但一定有火把。

输出格式

有几个点会生出怪物。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <stdio.h>
#include <stdlib.h>
#define MAX 100 // 定义网格的最大大小为 100x100

// 全局变量
int grid_size, torch_count, stone_count; // 网格大小、火把数量、石头数量
int torches[MAX][2]; // 存储火把的位置
int stones[MAX][2]; // 存储石头的位置
int illumination[MAX][MAX] = {0}; // 初始化照明矩阵,0 表示未被照亮,1 表示被照亮

// 照亮一个火把或石头周围的区域
// 只需要知道这个函数是用来统计火把的照亮区域的
void illuminate_area(int x, int y, int torch)
{
int dx, dy, nx, ny;
// 遍历火把周围的 5x5 区域
for (dx = -2; dx <= 2; dx++) //这个-2加上dx就相当于dx - 2
{
for (dy = -2; dy <= 2; dy++)
{
nx = x + dx; // 计算相对火把的 x 坐标
ny = y + dy; // 计算相对火把的 y 坐标

// 检查是否在网格范围内
if (nx >= 1 && nx <= grid_size && ny >= 1 && ny <= grid_size)
{
// 如果是火把,排除一些不规则区域(对角线和远处)
if (torch)
{
if ((abs(dx) == 2 && abs(dy) == 2) || // 排除四个角的点
(abs(dx) == 1 && abs(dy) == 2) || // 排除一些边缘位置
(abs(dx) == 2 && abs(dy) == 1))
{
continue; // 跳过这些点
}
}
// 将该位置标记为被照亮
illumination[nx-1][ny-1] = 1;
}
}
}
}

int main()
{
int i, j;
// 输入网格大小、火把数量、石头数量
scanf("%d %d %d", &grid_size, &torch_count, &stone_count);

// 输入火把的位置
for (i = 0; i < torch_count; i++)
{
scanf("%d %d", &torches[i][0], &torches[i][1]);
}

// 输入石头的位置,实际上这个没有被触发(测试环境中就不知道了)
for (i = 0; i < stone_count; i++)
{
scanf("%d %d", &stones[i][0], &stones[i][1]);
}

// 处理每个火把的照明范围
for (i = 0; i < torch_count; i++)
{
illuminate_area(torches[i][0], torches[i][1], 1);
}

// 处理每块石头的遮挡范围(石头不影响照明),这个实际上也没用到(测试环境中不清楚)
for (i = 0; i < stone_count; i++)
{
illuminate_area(stones[i][0], stones[i][1], 0);
}

// 统计没有被照亮的暗点
int dark_spots = 0;
for (i = 0; i < grid_size; i++)
{
for (j = 0; j < grid_size; j++)
{
if (illumination[i][j] == 0) // 该点没有被照亮
{
dark_spots++; // 统计暗点
}
}
}

// 输出暗点的数量
printf("%d\n", dark_spots);

return 0;
}

初始化变量和输入:

  • grid_size:网格的大小(grid_size x grid_size)。
  • torch_count:火把的数量。
  • stone_count:石头的数量。
  • torches[][]:存储每个火把的坐标。
  • stones[][]:存储每块石头的坐标。
  • illumination[][]:用于记录每个格子是否被照亮,初始值为 0

illuminate_area 函数:

  • 该函数用来照亮一个火把或石头周围的区域。
  • 如果是火把,它只照亮一个近似的十字形区域(排除对角线)。
  • 如果是石头,它照亮一个 5x5 的方形区域。

火把和石头处理:

  • 首先处理火把的照明区域,火把的照明范围是一个十字形(排除掉远处的点)。
  • 然后处理石头的影响,石头对照明的具体处理方式没有特别复杂的限制。

统计未被照亮的格子(暗点):

  • 遍历 illumination 数组,统计所有未被照亮的点,并输出结果。