C/C++编程(1~8级)全部真题・点这里
第1题:最短路径问题
平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。
若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
时间限制:1000
内存限制:131072
输入
共n+m+3行,其中: 第一行为整数n。 第2行到第n+1行(共n行) ,每行两个整数x和y,描述了一个点的坐标。 第n+2行为一个整数m,表示图中连线的个数。 此后的m 行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线。 最后一行:两个整数s和t,分别表示源点和目标点。
输出
仅一行,一个实数(保留两位小数),表示从s到t的最短路径长度。
样例输入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
样例输出
3.41
以下是一个解决最短路径问题的C语言程序:
#include <stdio.h>
#include <math.h>#define MAXN 101typedef struct {int x, y;
} Point;double dist(Point p1, Point p2) {int dx = p2.x - p1.x;int dy = p2.y - p1.y;return sqrt(dx * dx + dy * dy);
}int main() {int n;scanf("%d", &n);Point points[MAXN];int i;for (i = 0; i < n; i++) {scanf("%d %d", &points[i].x, &points[i].y);}int m;scanf("%d", &m);int edges[MAXN][MAXN] = {0};int j;for (j = 0; j < m; j++) {int u, v;scanf("%d %d", &u, &v);edges[u][v] = 1;edges[v][u] = 1;}int s, t;scanf("%d %d", &s, &t);double dist[MAXN];int visited[MAXN] = {0};for (i = 0; i < n; i++) {dist[i] = INFINITY;}dist[s] = 0;for (i = 0; i < n - 1; i++) {int minDistIndex = -1;double minDist = INFINITY;for (j = 0; j < n; j++) {if (!visited[j] && dist[j] < minDist) {minDist = dist[j];minDistIndex = j;}}visited[minDistIndex] = 1;for (j = 0; j < n; j++) {if (!visited[j] && edges[minDistIndex][j] && dist[minDistIndex] + dist(points[minDistIndex], points[j]) < dist[j]) {dist[j] = dist[minDistIndex] + dist(points[minDistIndex], points[j]);}}}printf("%.2lf\n", dist[t]);return 0;
}
在这个解决方案中,我们使用了Dijkstra算法来求解最短路径问题。
首先,我们定义了一个结构体Point
来表示平面上的点,包含x和y坐标。
然后,我们定义了一个dist
函数来计算两点之间的直线距离。
在主函数中,我们首先读取输入的点的数量n。
然后,我们读取n行,每行包含两个整数x和y,表示一个点的坐标。
接下来,我们读取连线的数量m。
然后,我们读取m行,每行包含两个整数i和j,表示第i个点和第j个点之间有连线。
最后,我们读取源点s和目标点t。
接下来,我们创建一个邻接矩阵edges
来表示点之间的连线关系。将连线的两个点在邻接矩阵中标记为1,表示有连线。
我们还创建一个距离数组dist
来存储从源点到各个点的最短距离。
然后,我们进行n-1轮迭代,每次选择距离最小的未访问点,更新该点到其他未访问点的距离。
最后,输出从源点到目标点的最短路径长度。
综上所述,这个C语言程序可以根据输入的点的坐标和连线关系,求解从源点到目标点的最短路径长度,并输出结果。
第2题:Freda的越野跑
Freda报名参加了学校的越野跑。越野跑共有N人参加,在一条笔直的道路上进行。这N个人在起点处站成一列,相邻两个人之间保持一定的间距。比赛开始后,这N个人同时沿着道路向相同的方向跑去。换句话说,这N个人可以看作x轴上的N个点,在比赛开始后,它们同时向x轴正方向移动。
假设越野跑的距离足够远,这N个人的速度各不相同且保持匀速运动,那么会有多少对参赛者之间发生“赶超”的事件呢?
时间限制:1000
内存限制:262144
输入
第一行1个整数N。 第二行为N 个非负整数,按从前到后的顺序给出每个人的跑步速度。 对于50%的数据,2<=N<=1000。 对于100%的数据,2<=N<=100000。
输出
一个整数,表示有多少对参赛者之间发生赶超事件。
样例输入
5
1 3 10 8 5
样例输出
7
提示
我们把这5个人依次编号为A,B,C,D,E,速度分别为1,3,10,8,5。 在跑步过程中: B,C,D,E均会超过A,因为他们的速度都比A快; C,D,E都会超过B,因为他们的速度都比B快; C,D,E之间不会发生赶超,因为速度快的起跑时就在前边。
以下是一个解决Freda的越野跑问题的C语言程序:
#include <stdio.h>int main() {int N;scanf("%d", &N);int speeds[N];int i;for (i = 0; i < N; i++) {scanf("%d", &speeds[i]);}int count = 0;int maxSpeed = speeds[N - 1];for (i = N - 2; i >= 0; i--) {if (speeds[i] > maxSpeed) {count++;} else {maxSpeed = speeds[i];}}printf("%d\n", count);return 0;
}
在这个解决方案中,我们首先读取输入的参赛者数量N。
然后,我们创建一个长度为N的整数数组speeds
来存储每个参赛者的速度。
接下来,我们使用一个循环读取N个非负整数,分别表示每个参赛者的速度,并将其存储在数组speeds
中。
然后,我们初始化一个变量count
为0,用于计数赶超事件的数量。
我们还定义一个变量maxSpeed
,用于记录当前已经遍历的参赛者中的最大速度。
接下来,我们从倒数第二个参赛者开始向前遍历,比较每个参赛者的速度和当前最大速度。
如果某个参赛者的速度大于当前最大速度,说明发生了一次赶超事件,我们将count
加1。
否则,更新maxSpeed
为当前参赛者的速度,因为速度较慢的参赛者不会再被之后速度较快的参赛者赶超。
最后,输出count
,表示发生赶超事件的数量。
综上所述,这个C语言程序可以根据输入的参赛者速度,计算出有多少对参赛者之间发生赶超事件,并输出结果。
第3题:社交网络
随着社交平台的兴起,人们之间的沟通变得越来越密切。通过Facebook的分享功能,只要你是对方的好友,你就可以转发对方的状态,并且你的名字将出现在“转发链”上。经过若干次转发以后,很可能A分享了一条好友C的状态,而C的这条状态实际上是分享B的,但A与B可能并不是好友,即A通过C间接分享了B的状态。
给定你N个人之间的好友关系,好友关系一定是双向的。只要两个人是好友,他们就可以互相转发对方的状态,无论这条状态是他自己的,还是他转发了其他人的。现在请你统计,对于每两个人,他们是否有可能间接转发对方的状态。
时间限制:1000
内存限制:262144
输入
第一行1个整数N(1<=N<=300)。 接下来N行每行N个整数,表示一个NN的01矩阵,若矩阵的第i行第j列是1,表示这两个人是好友,0则表示不是好友。 保证矩阵的主对角线上都是1,并且矩阵关于主对角线对称。
输出
一个NN的01矩阵,若矩阵的第i行第j列是1,表示这两个人可能间接转发对方的状态,0则表示不可能。
样例输入
5
11000
11100
01100
00011
00011
样例输出
11100
11100
11100
00011
00011
提示
在输入数据中,1与2是好友,2与3是好友,4与5是好友。 因此1、2、3有可能互相转发状态;4、5有可能互相转发状态。这两组人之间则不可能。
以下是一个解决社交网络问题的C语言程序:
#include <stdio.h>void calculateIndirectConnections(int N, int friends[][N], int indirectConnections[][N]) {int i, j, k;// 初始化indirectConnections矩阵为friends矩阵的拷贝for (i = 0; i < N; i++) {for (j = 0; j < N; j++) {indirectConnections[i][j] = friends[i][j];}}// 使用Warshall算法计算间接转发关系for (k = 0; k < N; k++) {for (i = 0; i < N; i++) {for (j = 0; j < N; j++) {if (indirectConnections[i][k] && indirectConnections[k][j]) {indirectConnections[i][j] = 1;}}}}
}int main() {int N;scanf("%d", &N);int friends[N][N];int i, j;for (i = 0; i < N; i++) {for (j = 0; j < N; j++) {scanf("%d", &friends[i][j]);}}int indirectConnections[N][N];calculateIndirectConnections(N, friends, indirectConnections);// 输出indirectConnections矩阵for (i = 0; i < N; i++) {for (j = 0; j < N; j++) {printf("%d", indirectConnections[i][j]);}printf("\n");}return 0;
}
在这个解决方案中,我们首先读取输入的人数N。
然后,我们创建一个大小为N×N的二维数组friends
,用于存储好友关系。我们使用两层循环读取N行N列的二进制矩阵,并将其存储在friends
数组中。
接下来,我们创建一个大小为N×N的二维数组indirectConnections
,用于存储间接转发关系。我们将friends
数组的内容复制到indirectConnections
数组中,作为初始的间接转发关系。
然后,我们使用Warshall算法来计算间接转发关系。通过三重循环遍历indirectConnections
数组,如果第i个人与第k个人以及第k个人与第j个人存在间接转发关系,则更新第i个人与第j个人之间的间接转发关系为1。
最后,我们输出indirectConnections
矩阵,即每两个人之间可能的间接转发关系。
综上所述,这个C语言程序可以根据好友关系,计算出每两个人之间是否可能存在间接转发关系,并输出结果。
第4题:旅行
转眼毕业了,曾经朝夕相处的同学们不得不都各奔东西,大家都去了不同的城市开始新的生活。在各自城市居住了一段时间后,他们都感到了一些厌倦,想去看看其他人的生活究竟如何,于是他们都选择到另一个同学所在城市去旅游,并且希望旅游的城市各不相同,他们想知道有多少种不同的方案,可是数量实在太多了,他们无法计算出来,你能帮助他们吗。
时间限制:10000
内存限制:131072
输入
一个正整数n(n<200),表示人数。
输出
一个数,表示有多少不同的方案。
样例输入
3
样例输出
2
提示
有如下两种方案: 同学1去同学2的城市,同学2去同学3的城市,同学3去同学1的城市; 同学1去同学3的城市,同学3去同学2的城市,同学2去同学1的城市。
这个问题可以使用动态规划来解决。我们可以将旅行的方案数量表示为一个状态转移方程,并使用动态规划的方法计算出所有可能的方案数量。
以下是一个解决旅行问题的C语言程序:
#include <stdio.h>#define MAX_N 200long long int travelPlans(int n) {// 创建一个大小为n的数组,用于存储状态转移方程的结果long long int dp[MAX_N];// 初始化dp数组dp[1] = 0;dp[2] = 1;int i;for (i = 3; i <= n; i++) {// 使用状态转移方程计算dp[i]dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]);}return dp[n];
}int main() {int n;scanf("%d", &n);long long int result = travelPlans(n);printf("%lld\n", result);return 0;
}
在这个解决方案中,我们首先读取输入的人数n。
然后,我们创建一个大小为MAX_N的数组dp
,用于存储状态转移方程的结果。
接下来,我们初始化dp
数组的前两个元素,dp[1]为0,dp[2]为1。
然后,我们使用一个循环从3到n,计算dp[i]的值。根据状态转移方程,dp[i]等于(i-1)乘以(dp[i-1]+dp[i-2])。
最后,我们输出dp[n],即旅行的方案数量。
综上所述,这个C语言程序可以根据输入的人数,计算出旅行的不同方案数量,并输出结果。