> 文档中心 > 练——C语言练习蚂蚁感冒

练——C语言练习蚂蚁感冒


提示:自己做的可能复杂,请各位大佬指正

文章目录

  • 一、题目
  • 二、思路
  • 三、实现的过程
    • 1.主函数
    • 2.初始感冒蚂蚁的设置
    • 3.感冒蚂蚁的判定
  • 总结

一、题目

长100厘米的细长直杆子上有n只蚂蚁。它们的头有的朝左,有的朝右。每只蚂蚁都只能沿着杆子向前爬,速度是1厘米/秒。当两只蚂蚁碰面时,它们会同时掉头往相反的方向爬行。这些蚂蚁中,有1只蚂蚁感冒了。并且在和其它蚂蚁碰面时,会把感冒传染给碰到的蚂蚁。请你计算,当所有蚂蚁都爬离杆子时,有多少只蚂蚁患上了感冒,并列出哪几只蚂蚁感冒了。
第一行输入一个整数n (1 < n < 50), 表示蚂蚁的总数。接着的一行是n个用空格分开的整数 Xi (-100 < Xi < 100), Xi的绝对值,表示蚂蚁离开杆子左边端点的距离。正值表示头朝右,负值表示头朝左,数据中不会出现0值,也不会出现两只蚂蚁占用同一位置。(其中,哪只蚂蚁感冒是随机的)
示例
练——C语言练习蚂蚁感冒
练——C语言练习蚂蚁感冒


二、思路

这道题原本我是想的如果碰面就掉头这种情况去算,但是发现思路过于复杂,而且代码不是很好写(当然如果有大佬可以这样写出来的话,可否让我看一下下),所以思考了好久。观察题中所给的示例发现,如果两个蚂蚁碰头,他们除了朝向与原先不同(当然如果其中有一只感冒,那么另一只会感冒)外,他们的速度,碰撞后的位置均相同,那么不妨假设,如果两个蚂蚁碰面后并没有转头,而是穿过了彼此的身体继续向前走,那么就会变得简单一点,以题中所给的例子为例
在这里插入图片描述
假设如果最初处于-20的蚂蚁感冒,那么假设碰撞后彼此穿越身体的话,5只蚂蚁均感冒,但是如果最初处于12的蚂蚁感冒的话,那么处于25位置的蚂蚁最终不会感冒,剩下四只均感冒,那么大概可以得出如下结论:
如果所有蚂蚁初始朝向均相同,那么最终只有1只蚂蚁感冒,且那只蚂蚁为最初感冒的那只,而如果最初有一些蚂蚁与感冒的蚂蚁朝向不同,那么进行再进行判断,
(1)如果与最初感冒蚂蚁朝向不同的蚂蚁已经在感冒蚂蚁的身后,那么不会感冒,反之,如果在身前,那么会感冒(用代数表达就是两个蚂蚁最初位置的差的绝对值如果大于100那么不会感冒,反之会感冒),
(2)而与感冒蚂蚁相同朝向且在它身后的蚂蚁是否感冒取决于(1),如果(1)为真(即有朝向相反的蚂蚁被传染感冒),那么蚂蚁感冒,反之蚂蚁不感冒(语言不是很好,多多见谅)


三、实现的过程

通过以上的思路,我们发现主函数并不困难,我们所需要的只是输入蚂蚁的个数以及将每个蚂蚁的位置去存入一个数组中即可,然后通过设置一个计算函数去完成。这个数组中第一行放置所有蚂蚁的位置,而第二行放置的数字为感冒蚂蚁分别为第几只蚂蚁,而此顺序并不一定是感染顺序,例如下图
练——C语言练习蚂蚁感冒
该结果显示第2只蚂蚁(位置处于-20)为初始感冒蚂蚁,而其后被感染的蚂蚁为第三只(位置处于12),第一只(位置处于-10),第四只(位置处于8),第五只(位置处于25),其中第三只并不是第一只被初始感冒蚂蚁所感染的蚂蚁(其实真实情况是第五只蚂蚁为第一只被感染的蚂蚁),并且最后的感冒总数为5。那么代码我们可以写成这样。

1.主函数

#include #include #include int main(){    int n, a[2][50], s = 1;///s为感冒蚂蚁的个数    printf("Please input a number n:");    scanf("%d", &n);///输入一共有多少只蚂蚁    for (int i = 0; i < n; i++) scanf("%d", &a[0][i]);///输入每一只蚂蚁所在的位置    candiate(n, &a[0], &s);///传入每个蚂蚁的位置并计算感冒蚂蚁的个数以及他们分别属于第几只蚂蚁    printf("\ns=%d\n", s);    return 0;}

2.初始感冒蚂蚁的设置

而主函数中的candiate函数就是我们所需要解决的重点与难点,而最开始我们需要设定一只幸运的蚂蚁去当初始感冒蚂蚁(由于数组是从0开始,而蚂蚁的个数从1开始,并且随机数的范围是在[0,n-1]中,所以在产生随机数后我们需要将其加一,才可以得到初始感冒蚂蚁为第几只蚂蚁,例如我们随机值为1,其所表达的是第一列数组中a[1]蚂蚁感冒,即第二只感冒)

int j, key1 = 0, key2 = 1, number;    srand((unsigned)time(NULL));///随机挑选一个幸运的蚂蚁感冒    j = rand() % s;///因为随机的是数组下标所以要求生成的随机数在[0,n-1]之内    *(*(a + 1)) = j + 1;///将最初感冒的蚂蚁保存在数组的第二行的第一个元素中

3.感冒蚂蚁的判定

这里我分了两种情况,初始感冒蚂蚁是向左移动还是向右移动。

if (a[0][j] > 0)///如果感冒的蚂蚁向右爬    { for (int m = 0, c = 1; m < s; m++) {     number = c;     if (a[0][m] < 0 && a[0][j] - a[0][m] < 100)///如果满足条件(1)那么感冒蚂蚁个数增加并且将其初始位置记录到数组第二列中     {  *(*(a + 1) + c) = m + 1;  c++;  *sum += 1;  key1 = 1;     }     if (key1 == 1 && key2 == 1)///设置两个开关是为了防止满足条件(2)的蚂蚁多次重复被记录到数组第二列中,如果条件(1)成立,那么在完成记录满足条件(2)的蚂蚁个数与位置后立即关闭key2  for (int t = 0; t < s; t++)      if (*(*a + t) < *(*a + j) && *(*a + t) > 0)      {   *(*(a + 1) + c) = t + 1, * sum += 1;   c++;   key2 = 0;      } } for (int m = 0; m < number; m++)///列举出所有感冒的蚂蚁     printf("%d ", *(*(a + 1) + m));///其中第一个元素为初始感冒蚂蚁所在的位置    }

key1,key2的设置是为了防止多次判断满足条件(2)的蚂蚁是否存在而导致重复计数。

 if (a[0][j] < 0)///如果蚂蚁向左爬    { for (int m = 0, c = 1; m < s; m++) {     number = c;     if (a[0][m] > 0 && a[0][j] - a[0][m] > -100)///情况于上面相同     {  *(*(a + 1) + c) = m + 1;  c++;  *sum += 1;  key1 = 1;     }     if (key1 == 1 && key2 == 1)  for (int t = 0; t < s; t++)      if ((*(*a + t) > *(*a + j)) && *(*a + t) < 0)      {   *(*(a + 1) + c) = t + 1, * sum += 1;   c++;   key2 = 0;      } } for (int m = 0; m <= number; m++)///列举出所有感冒的蚂蚁     printf("%d ", *(*(a + 1) + m));///其中第一个元素为初始感冒蚂蚁所在的位置    }

综上,我们最后写出如下代码

#include #include #include void candiate(int s, int(*a)[50], int* sum);///计算有多少只蚂蚁感冒int main(){    int n, a[2][50], s = 1;    printf("Please input a number n:");    scanf("%d", &n);    for (int i = 0; i < n; i++) scanf("%d", &a[0][i]);    candiate(n, &a[0], &s);    printf("\ns=%d\n", s);    return 0;}void candiate(int s, int(*a)[50], int* sum){    int j, key1 = 0, key2 = 1, number;    srand((unsigned)time(NULL));///随机挑选一个幸运的蚂蚁感冒    j = rand() % s;///因为随机的是数组下标所以要求生成的随机数在[0,n-1]之内    *(*(a + 1)) = j + 1;///将最初感冒的蚂蚁保存在数组的第二行的第一个元素中    if (a[0][j] > 0)///如果感冒的蚂蚁向右爬    { for (int m = 0, c = 1; m < s; m++) {     number = c;     if (a[0][m] < 0 && a[0][j] - a[0][m] < 100)///如果满足条件(1)那么感冒蚂蚁个数增加并且将其初始位置记录到数组第二列中     {  *(*(a + 1) + c) = m + 1;  c++;  *sum += 1;  key1 = 1;     }     if (key1 == 1 && key2 == 1)///设置两个开关是为了防止满足条件(2)的蚂蚁多次重复被记录到数组第二列中,如果条件(1)成立,那么在完成记录满足条件(2)的蚂蚁个数与位置后立即关闭key2  for (int t = 0; t < s; t++)      if (*(*a + t) < *(*a + j) && *(*a + t) > 0)      {   *(*(a + 1) + c) = t + 1, * sum += 1;   c++;   key2 = 0;      } } for (int m = 0; m < number; m++)///列举出所有感冒的蚂蚁     printf("%d ", *(*(a + 1) + m));///其中第一个元素为初始感冒蚂蚁所在的位置    }    if (a[0][j] < 0)///如果蚂蚁向左爬    { for (int m = 0, c = 1; m < s; m++) {     number = c;     if (a[0][m] > 0 && a[0][j] - a[0][m] > -100)///情况于上面相同     {  *(*(a + 1) + c) = m + 1;  c++;  *sum += 1;  key1 = 1;     }     if (key1 == 1 && key2 == 1)  for (int t = 0; t < s; t++)      if ((*(*a + t) > *(*a + j)) && *(*a + t) < 0)      {   *(*(a + 1) + c) = t + 1, * sum += 1;   c++;   key2 = 0;      } } for (int m = 0; m <= number; m++)///列举出所有感冒的蚂蚁     printf("%d ", *(*(a + 1) + m));///其中第一个元素为初始感冒蚂蚁所在的位置    }}

总结

其实这个代码并不是很尽如人意,例如输出的顺序可以为被感染顺序,而且这个代码也有很多优化的地方,比如向左爬和向右爬几乎相同,所以应该可以进行合一,只不过自己现在代码能力还是太弱了。希望各位大佬能多多支持,指出其中的不足指出。阿里嘎多~