C/C++编程(1~8级)全部真题・点这里
人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在高峰这天,人会在相应的方面表现出色。例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。因为三个周期的周长不同,所以通常三个周期的高峰不会落在同一天。对于每个人,我们想知道何时三个高峰落在同一天。对于每个周期,我们会给出从当前年份的第一天开始,到出现高峰的天数(不一定是第一次高峰出现的时间)。你的任务是给定一个从当年第一天开始数的天数,输出从给定时间开始(不包括给定时间)下一次三个高峰落在同一天的时间(距给定时间的天数)。例如:给定时间为10,下次出现三个高峰同天的时间是12,则输出2(注意这里不是3)。
时间限制:1000
内存限制:65536
输入
一行,包含四个整数:p, e, i和d,相邻两个整数之间用单个空格隔开。 p, e, i分别表示体力、情感和智力高峰出现的时间(时间从当年的第一天开始计算)。d 是给定的时间,可能小于p, e, 或 i。 所有给定时间是非负的并且小于等于365, 所求的时间小于等于21252。
输出
一个整数,即从给定时间起,下一次三个高峰同天的时间(距离给定时间的天数)。
样例输入
4 5 6 7
样例输出
16994
以下是一个解决生理周期问题的C语言程序:
#include
int main() {
int p, e, i, d;
scanf("%d %d %d %d", &p, &e, &i, &d);
int caseNum = 1;
while (1) {
int days = caseNum * 21252 + d;
if ((days - p) % 23 == 0 && (days - e) % 28 == 0 && (days - i) % 33 == 0) {
printf("%d\n", caseNum * 21252);
break;
}
caseNum++;
}
return 0;
}
在这个解决方案中,我们首先读取输入的体力、感情和智力高峰出现的时间p、e和i,以及给定的时间d。
然后,我们使用一个循环来逐个尝试不同的案例,直到找到一个满足三个高峰同天的时间。
在每个案例中,我们计算出总天数days,通过caseNum * 21252 + d
计算得到,其中21252是三个周期的最小公倍数。
接下来,我们检查是否满足三个高峰同天的条件,即(days - p) % 23 == 0
、(days - e) % 28 == 0
和(days - i) % 33 == 0
。如果满足条件,则输出距离给定时间的天数caseNum * 21252
,并结束循环。
如果不满足条件,我们增加案例的数量caseNum,并继续下一个循环。
综上所述,这个C语言程序可以根据给定的体力、感情和智力高峰出现的时间,以及给定的时间,计算出从给定时间起,下一次三个高峰同天的时间(距离给定时间的天数)。
有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)
时间限制:1000
内存限制:65536
输入
输入第一行有一个数K,表示以下有K组测试数据。 每组测试数据的格式如下: 第一行 一个数N(0 < N < 29) 第二行 N个0或者1的数,表示开始时N个开关状态。 第三行 N个0或者1的数,表示操作结束后N个开关的状态。 接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。
输出
如果有可行方法,输出总数,否则输出“Oh,it’s impossible~!!” 不包括引号
样例输入
2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0
样例输出
4
Oh,it’s impossible~!!
提示
第一组数据的说明:一共以下四种方法: 操作开关1 操作开关2 操作开关3 操作开关1、2、3 (不记顺序)
以下是一个解决开关问题的C语言程序:
#include
#include
int N;
int initialStatus[29];
int targetStatus[29];
int connections[29][29];
int count = 0;
void dfs(int switchIndex) {
if (switchIndex > N) {
int i;
for (i = 1; i <= N; i++) {
if (initialStatus[i] != targetStatus[i]) {
return;
}
}
count++;
return;
}
initialStatus[switchIndex] = 1 - initialStatus[switchIndex];
int i;
for (i = 1; i <= N; i++) {
if (connections[switchIndex][i] == 1) {
initialStatus[i] = 1 - initialStatus[i];
}
}
dfs(switchIndex + 1);
initialStatus[switchIndex] = 1 - initialStatus[switchIndex];
for (i = 1; i <= N; i++) {
if (connections[switchIndex][i] == 1) {
initialStatus[i] = 1 - initialStatus[i];
}
}
dfs(switchIndex + 1);
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &N);
int i, j;
for (i = 1; i <= N; i++) {
scanf("%d", &initialStatus[i]);
}
for (i = 1; i <= N; i++) {
scanf("%d", &targetStatus[i]);
}
for (i = 1; i <= N; i++) {
for (j = 1; j <= N; j++) {
connections[i][j] = 0;
}
}
int I, J;
while (scanf("%d %d", &I, &J) == 2 && (I != 0 || J != 0)) {
connections[I][J] = 1;
}
count = 0;
dfs(1);
if (count > 0) {
printf("%d\n", count);
} else {
printf("Oh,it's impossible~!!\n");
}
}
return 0;
}
在这个解决方案中,我们首先定义了一个全局变量N来表示开关的数量,以及一些全局数组来存储开关的初始状态、目标状态和开关之间的联系。
然后,我们定义了一个递归函数dfs来尝试所有可能的开关操作。在dfs函数中,我们首先判断当前开关状态是否与目标状态相同,如果相同则将计数器count加1。
接下来,我们尝试操作当前开关,并更新与之相关联的开关状态。然后,递归调用dfs函数来继续处理下一个开关。
在递归调用之后,我们需要恢复当前开关和相关联开关的状态,以便尝试其他可能的操作。
在主函数中,我们首先读取输入的测试数据组数T。
然后,对于每组测试数据,我们读取开关的数量N,初始状态和目标状态。
接下来,我们读取开关之间的联系,并将其存储在connections数组中。
然后,我们调用dfs函数来尝试所有可能的开关操作,并根据计数器count的值输出结果。
综上所述,这个C语言程序可以根据输入的开关状态和联系,计算出达到指定状态的方法总数,或者判断无法达到指定状态。
老王喜欢喝冰阔落。
初始时刻,桌面上有n杯阔落,编号为1到n。老王总想把其中一杯阔落倒到另一杯中,这样他一次性就能喝很多很多阔落,假设杯子的容量是足够大的。
有m 次操作,每次操作包含两个整数x与y。
若原始编号为x 的阔落与原始编号为y的阔落已经在同一杯,请输出"Yes";否则,我们将原始编号为y 所在杯子的所有阔落,倒往原始编号为x 所在的杯子,并输出"No"。
最后,老王想知道哪些杯子有冰阔落。
时间限制:10000
内存限制:65536
输入
有多组测试数据,少于5 组。 每组测试数据,第一行两个整数 n, m (n, m<=50000)。接下来 m 行,每行两个整数 x, y (1<=x, y<=n)。
输出
每组测试数据,前m 行输出 “Yes” 或者 “No”。 第 m+1 行输出一个整数,表示有阔落的杯子数量。 第 m+2 行有若干个整数,从小到大输出这些杯子的编号。
样例输入
3 2
1 2
2 1
4 2
1 2
4 3
样例输出
No
Yes
2
1 3
No
No
2
1 4
以下是一个解决冰阔落问题的C语言程序:
#include
int parent[50001];
int count[50001];
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
void merge(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootY] = rootX;
count[rootX] += count[rootY];
}
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d %d", &n, &m);
int i;
for (i = 1; i <= n; i++) {
parent[i] = i;
count[i] = 1;
}
for (i = 0; i < m; i++) {
int x, y;
scanf("%d %d", &x, &y);
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY) {
printf("Yes\n");
} else {
printf("No\n");
merge(rootX, rootY);
}
}
int totalCups = 0;
for (i = 1; i <= n; i++) {
if (parent[i] == i) {
totalCups++;
}
}
printf("%d\n", totalCups);
for (i = 1; i <= n; i++) {
if (parent[i] == i) {
printf("%d ", i);
}
}
printf("\n");
}
return 0;
}
在这个解决方案中,我们使用并查集数据结构来处理冰阔落的问题。
首先,我们定义了两个数组parent
和count
,作为并查集的辅助数组。parent
数组用于记录每个杯子的父节点,count
数组用于记录每个集合(杯子所在的连通分量)的杯子数量。
在主函数中,我们首先读取输入的测试数据组数T。
然后,对于每组测试数据,我们读取阔落杯子的数量n和操作次数m,并初始化并查集数组。
接下来,我们循环读取每次操作的两个杯子编号x和y。
对于每次操作,我们首先判断两个杯子是否在同一个连通分量(集合)中,即它们的根节点是否相同。如果根节点相同,则输出"Yes"。
如果根节点不同,则输出"No",并将两个集合进行合并,即将其中一个集合的根节点的父节点设置为另一个集合的根节点,并更新合并后集合的杯子数量。
完成所有操作后,我们统计并输出有阔落的杯子数量。遍历数组parent
,找到根节点为自身的杯子,即代表一个集合的根节点,输出它们的编号。
综上所述,这个C语言程序可以根据输入的冰阔落操作,输出每次操作的结果以及最终有阔落的杯子数量和它们的编号。
给定一个n个点, m条边的有向图, 求从点S出发, 到其它所有点的最短路径.
时间限制:2000
内存限制:65536
输入
第一行一个整数T, 表示有T组数据 对于每组测试数据, 第一行三个整数n, m, S, 表示有n个点, m条边, 起点为S. 接下来m行, 每行三个整数x, y, z, 代表从x到y有长度为z的边 点的编号从1到n T <= 10, n <= 10000, m <= 20000, |z| <= 10000. 所有数据的n之和 <= 30000, 所有数据的m之和 <= 60000.
输出
对于每组数据: 如果从S点出发可以走入负圈 (即到某些点的最短路径可以无限小), 那么输出一行Error. 否则, 输出一行用空格分隔的n个整数, 其中第i个整数表示从S点到i点的最短路长度. 如果从S点无法到达i点, 则第i个输出为”null”.
样例输入
4
5 7 1
1 2 3
2 3 4
3 4 8
1 3 9
4 5 1
1 4 5
1 5 10
4 4 1
1 2 -4
2 3 8
1 3 5
3 4 0
3 3 2
1 2 -3
2 3 -4
3 1 6
4 2 1
1 2 1
3 4 2
样例输出
0 3 7 5 6
0 -4 4 4
Error
0 1 null null
以下是一个解决最短路问题的C语言程序:
#include
#include
#include
#define MAXN 10001
#define MAXM 20001
typedef struct {
int u, v, w;
} Edge;
int dist[MAXN];
Edge edges[MAXM];
void BellmanFord(int n, int m, int s) {
int i, j;
// 初始化距离数组
for (i = 1; i <= n; i++) {
dist[i] = INT_MAX;
}
dist[s] = 0;
// 进行n-1轮松弛操作
for (i = 1; i <= n - 1; i++) {
for (j = 0; j < m; j++) {
int u = edges[j].u;
int v = edges[j].v;
int w = edges[j].w;
if (dist[u] != INT_MAX && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
// 检查是否存在负圈
bool hasNegativeCycle = false;
for (j = 0; j < m; j++) {
int u = edges[j].u;
int v = edges[j].v;
int w = edges[j].w;
if (dist[u] != INT_MAX && dist[u] + w < dist[v]) {
hasNegativeCycle = true;
break;
}
}
// 输出结果
if (hasNegativeCycle) {
printf("Error\n");
} else {
for (i = 1; i <= n; i++) {
if (dist[i] != INT_MAX) {
printf("%d ", dist[i]);
} else {
printf("null ");
}
}
printf("\n");
}
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, m, s;
scanf("%d %d %d", &n, &m, &s);
int i;
for (i = 0; i < m; i++) {
scanf("%d %d %d", &edges[i].u, &edges[i].v, &edges[i].w);
}
BellmanFord(n, m, s);
}
return 0;
}
在这个解决方案中,我们使用了Bellman-Ford算法来求解最短路问题。
首先,我们定义了一个结构体Edge
来表示图中的边,包含起点、终点和边的权重。
然后,我们定义了一个距离数组dist
用于存储从起点到各个点的最短路长度。
在BellmanFord
函数中,我们首先对距离数组进行初始化,将起点的距离设置为0,其余点的距离设置为无穷大。
然后,我们进行n-1轮松弛操作,遍历所有边,根据边的权重更新起点到终点的距离,如果找到了更短的路径,则更新距离数组。
接下来,我们检查是否存在负圈,即进行第n轮松弛操作,如果仍然能够找到更短的路径,则说明存在负圈。
最后,根据是否存在负圈来输出结果。如果存在负圈,则输出"Error";否则,输出从起点到各个点的最短路长度。
在主函数中,我们首先读取输入的测试数据组数T。
然后,对于每组测试数据,我们读取点的数量n、边的数量m和起点S,以及m行描述边的信息。
最后,我们调用BellmanFord
函数来求解最短路问题,并输出结果。
综上所述,这个C语言程序可以根据输入的有向图和起点,求解从起点到其它所有点的最短路径,并输出结果。如果存在负圈,则输出"Error"。