当前位置: 首页 > news >正文

22 程序控制语句详解:跳转控制(break、continue、goto)、死循环应用、程序控制编程实战

1 break 语句

1.1 介绍

        break 语句用于立即终止当前所在的循环或 switch 语句块的执行,将程序控制权转移到该语句块之后的下一条语句

  • 循环语句:提前退出循环体(仅退出最近的封闭循环)。
  • switch 语句:防止代码 "穿透" 执行下一个 case 分支。

1.2 功能流程图

1.3 在循环中使用 break

        break 语句在循环中用于在满足特定条件时提前终止循环,跳过循环中剩余的语句和后续的循环迭代。 

#include <stdio.h>int main()
{for (int i = 0; i < 10; i++){if (i == 3){break; // 当 i=3 时终止循环}printf("%d \t", i); // 输出: 0 1 2}return 0;
}

        程序在 VS Code 中的运行结果如下所示:

1.4 嵌套循环中的 break

        在嵌套循环中,break 只会终止最近的封闭循环(内层循环),外层循环不受影响

#include <stdio.h>int main()
{for (int i = 1; i <= 3; i++){printf("外层循环:i = %d\n", i);for (int j = 1; j <= 5; j++){if (j == 4){break; // 只退出内层循环}printf("  内层循环:j = %d\n", j);}}return 0;
}

        程序在 VS Code 中的运行结果如下所示:

1.5 案例:质数判断

        编写一个程序,要求用户输入一个数字,判断该数字是否是质数(又称素数,是指在大于 1 的自然数中,除了 1 和它本身以外,不能被其他自然数整除的数)

方法一:使用布尔类型(C99 及以上)

#include <stdio.h>
#include <stdbool.h> // 引入布尔类型支持int main()
{int num;printf("请输入一个正整数:");scanf("%d", &num);// 初始化质数标志// 质数是大于 1 的自然数,且只能被 1 和它本身整除// 这里使用三元运算符来初始化 isPrime// 如果 num 小于等于 1,则不是质数,否则是质数bool isPrime = num > 1 ? true : false;// 如果 num 大于 1,则进行质数判断// 从 2 开始判断到 num 的一半// 因为一个数的因数不可能大于它的一半// 例如:6 的因数是 1, 2, 3, 6,最大因数是 3for (int i = 2; i <= num / 2; i++){if (num % i == 0){isPrime = false; // 发现因数,不是质数}}// 输出结果if (isPrime) // 如果 isPrime 为 true,则 num 是质数{printf("%d 是质数。\n", num);}else // 如果 isPrime 为 false,则 num 不是质数{printf("%d 不是质数。\n", num);}return 0;
}

方法二:使用整型标志(兼容所有 C 版本)

#include <stdio.h>int main()
{int num;printf("请输入一个正整数:");scanf("%d", &num);// 初始化质数标志(1 表示 true,0 表示 false)// 质数是大于 1 的自然数,且只能被 1 和它本身整除// 这里使用三元运算符来初始化 isPrime// 如果 num 小于等于 1,则不是质数,否则是质数int isPrime = num > 1 ? 1 : 0;// 如果 num 大于 1,则进行质数判断// 从 2 开始判断到 num 的一半// 因为一个数的因数不可能大于它的一半// 例如:6 的因数是 1, 2, 3, 6,最大因数是 3for (int i = 2; i <= num / 2; i++){if (num % i == 0){isPrime = 0; // 发现因数,不是质数}}// 输出结果if (isPrime){printf("%d 是质数。\n", num);}else{printf("%d 不是质数。\n", num);}return 0;
}

程序优化:

  1. 将循环上限从 num/2 优化为 sqrt(num)(通过 i*i <= num 实现)。
  2. 在循环条件中加入 && isPrime,使得一旦确定非质数就立即终止循环。
  3. 使用三元运算符简化输出语句,添加更友好的用户提示。
#include <stdio.h>int main()
{int num;printf("请输入一个正整数:");scanf("%d", &num);// 初始化质数标志(1 表示 true,0 表示 false)// 质数是大于 1 的自然数,且只能被 1 和它本身整除// 这里使用三元运算符来初始化 isPrime// 如果 num 小于等于 1,则不是质数,否则是质数int isPrime = num > 1 ? 1 : 0;// 如果 num 大于 1,则进行质数判断// 将循环上限从 num / 2 优化为 sqrt(num) (通过 i *i <= num 实现)// 因为一个数的因数不可能大于它的平方根(可能比一半要小,优化循环次数)// 在循环条件中加入 && isPrime,使得一旦确定非质数就立即终止循环for (int i = 2; i * i <= num && isPrime; i++){if (num % i == 0){isPrime = 0; // 发现因数,标记为非质数}}// 输出结果// %s 用于格式化字符串,在 printf 中使用可以输出字符串printf("%d %s质数!\n", num, isPrime ? "是" : "不是");return 0;
}

        程序在 VS Code 中的多次运行结果如下所示:

提示:

  • 质数判断只需检查到平方根即可,这是数学上的优化。
  • %s 用于格式化字符串,在 printf 中使用可以输出字符串。 

1.6 注意事项

  1. 使用范围限制:break 只能用于 switch 或循环语句中,在其它地方使用会导致编译错误
  2. 嵌套循环处理:break 只能退出当前所在循环,多层退出需使用多个 break 或标志变量
  3. switch 语句中的穿透效应:在 switch 中可以使用 break 防止执行不需要的 case 分支。
  4. 替代方案:对于复杂嵌套循环,可考虑使用 goto 语句(虽不推荐,但在某些场景下是合理选择)。

1.7 最佳实践

  • 在简单循环中优先使用 break 提前退出。
  • 对于嵌套循环,考虑重构代码或使用标志变量控制外层循环。
  • 在 switch 语句中建议始终为每个 case 添加明确的 break(除非有意利用穿透特性)。

2 continue 语句

2.1 介绍

        continue 是循环控制语句,只能用于 for、while 或 do-while 循环中

        它的作用是跳过当前循环迭代的剩余部分,直接进入下一次循环

    2.2 功能流程图

    2.3 在循环中使用 continue

            continue 语句用于控制循环流程,当满足特定条件时跳过当前迭代的剩余部分,直接进入下一次循环迭代

    • 跳过当前迭代:当 continue 被执行时,循环体中 continue 之后的代码将被忽略。
    • 进入下一次迭代:立即开始下一次循环检查(对于 for 循环,会先执行迭代部分)。
    #include <stdio.h>int main()
    {// 示例:打印 1-10,跳过数字 5for (int i = 1; i <= 10; i++){if (i == 5){continue; // 跳过数字 5}printf("%d ", i);}return 0;
    }

            程序在 VS Code 中的运行结果如下所示:

    2.4 嵌套循环中的 continue

            在嵌套循环中,continue 只影响最内层的循环。如果需要影响外层循环,需要使用标记变量或 goto(不推荐)。

    #include <stdio.h>int main()
    {for (int i = 1; i <= 3; i++){printf("外层循环:i = %d\n", i);for (int j = 1; j <= 4; j++){if (j == 3){continue; // 只跳过内层循环的当前迭代}printf("  内层循环:j = %d\n", j);}}return 0;
    }

            程序在 VS Code 中的运行结果如下所示:

    2.5 案例:逢七过游戏

            实现一个 "逢七过" 游戏,输出 1 到 100(包含 1 和 100)的数字,但需要跳过以下数字:

    1. 7 的倍数
    2. 包含数字 7 的数字(个位或十位为 7)
    #include <stdio.h>int main()
    {int counter = 0; // 计数器,用于记录输出的数字个数// 循环从 1 到 100for (int i = 1; i <= 100; i++){// 检查当前数字是否是 7 的倍数,个位数是否为 7,或者十位数是否为 7if (i % 7 == 0 || i % 10 == 7 || i / 10 == 7){continue; // 如果条件满足,跳过当前数字}printf("%d ", i); // 输出符合条件的数字counter++;        // 增加计数器// 每 10 个数字换行if (counter % 10 == 0){printf("\n");}}return 0;
    }
    

            程序在 VS Code 中的运行结果如下所示:

    2.6 注意事项

    1. 与 break 的区别:

    • continue:跳过当前迭代,继续下一次循环
    • break:完全终止循环

    2. 循环变量更新:

    • 在 while 循环中,确保 continue 不会跳过循环变量的更新
    • 错误的 continue 放置可能导致无限循环。
    • 错误示例:
    #include <stdio.h>int main()
    {// 错误:可能导致无限循环int i = 0;while (i < 5){if (i % 2 == 0){continue; // 跳过 i 的递增}printf("%d", i);i++;}return 0;
    }
    • 正确写法:
    #include <stdio.h>int main()
    {int i = 0;while (i < 5){if (i % 2 == 0){printf("跳过偶数: %d\n", i);i++; // 这里需要先自增,否则会陷入死循环continue;}printf("奇数: %d\n", i);i++; // 自增}return 0;
    }

    2.7 最佳实践

    1. 明确使用场景:

    1. 只在确实需要跳过当前迭代时使用 continue。
    2. 避免滥用,特别是简单的 if-else 结构可以替代时。

    2. 代码可读性:

    1. 复杂条件拆分为多个 if 语句:
    // 不推荐
    if (condition1 && condition2 || condition3) {continue;
    }// 推荐
    if (condition1) {if (condition2 || condition3) {continue;}
    }

    3. 循环变量安全:

    1. 在 while 循环中,确保 continue 不会跳过循环变量的更新
    2. 考虑将循环变量的更新放在循环开始处。

    4. 注释说明:

    1. 对复杂的 continue 使用添加注释,说明跳过的原因。

    5. 替代方案:

    1. 对于简单的条件判断,考虑使用 if-else 结构替代 continue:
    // 使用 continue
    for (...) {if (condition) continue;// 执行代码
    }// 替代方案
    for (...) {if (!condition) {// 执行代码}
    }

    3 goto 语句

    3.1 介绍

            goto 语句是一个无条件跳转语句它允许程序跳转到同一函数或同一作用域块内的指定标签(label)处继续执行。标签名称需符合标识符规范。

      3.2 语法格式

      goto label_name;  // 跳转到指定标签
      // ...
      label_name:       // 定义标签statement;    // 跳转到这里执行
      • 注意:goto 后面引用了未定义的标签会导致编译错误。 

      3.3 功能流程图

      3.4 案例:跳过代码块

      #include <stdio.h>int main()
      {printf("Start \n"); // 开始// 跳转到标签 label1 处执行goto label1; // 跳过下面的两条打印语句// 以下语句由于 goto 的存在不会被执行printf("ok1 \n"); // 跳过printf("ok2 \n"); // 跳过label1:// 跳转到这里执行printf("ok3 \n"); // 执行printf("ok4 \n"); // 执行printf("End \n"); // 结束return 0;
      }

              程序在 VS Code 中的运行结果如下所示:

      3.5 案例:条件跳过循环

      #include <stdio.h>int main()
      {int i = 11;// 使用 goto 跳转到循环结束标签if (i > 10){goto end_loop; // 直接跳转到循环结束标签}// 以下循环不会执行for (i = 0; i < 5; i++){printf("i = %d\n", i); // 这行不会执行}end_loop:printf("跳过上面的循环-未执行循环\n");return 0;
      }

              程序在 VS Code 中的运行结果如下所示:

      3.6 使用 goto 实现循环

              虽然不推荐,但 goto 可以用于实现循环逻辑:

      #include <stdio.h>int main()
      {int i = 1; // 初始化计数器start: // 定义循环起始标签if (i <= 5) // 循环条件{printf("%d ", i); // 打印当前值i++;              // 递增计数器goto start;       // 跳回循环起始处}return 0; // 循环结束
      }

              程序在 VS Code 中的运行结果如下所示:

      3.7 注意事项

      1. 关键限制:

      • 不能跨函数跳转(不能从一个函数跳转到另一个函数的标签)
      • 不能跨多层嵌套作用域跳转
      • 只能跳转到同一函数内的标签

      2. 使用建议:

      • 通常被认为是不良编程实践,可能导致代码难以理解和维护。
      • 不建议在常规开发中使用。
      • 需要理解其执行流程以阅读包含 goto 的代码。

      3.8 最佳实践

      1. 避免使用:在大多数情况下,使用结构化控制流(for、while、do-while)更可取。
      2. 有限使用场景:
        • 从深层嵌套中跳出(但通常有更好的结构化解决方案)。
        • 某些特定算法实现(如状态机)。
      3. 代码可读性:
        • 如果必须使用,添加详细注释说明原因。
        • 保持标签命名清晰且有意义。
      4. 替代方案:
        • 使用 break 和 continue 控制循环。
        • 使用函数封装复杂逻辑。
        • 使用标志变量控制流程。

              goto 语句虽然功能强大,但会破坏程序的结构化特性,应谨慎使用。在绝大多数情况下,结构化编程技术可以提供更清晰、更易维护的解决方案。


      4 死循环

      4.1 介绍

              死循环(Infinite Loop)是指一种无法自行终止的循环结构,程序会一直重复执行循环体内的代码,除非被外部干预(如用户中断、系统信号或程序异常)。具有以下特点:

      • 循环条件始终为真。
      • 不会自然退出。
      • 通常需要明确的退出机制(如 break 语句)。

      4.2 死循环的实现方式

      使用 while 循环

      while (1) {// 循环体代码// 需要 break 语句或其他方式退出
      }

      使用 do-while 循环

      do {// 循环体代码// 需要 break 语句或其他方式退出
      } while (1);

      使用 for 循环

      for (;;) {// 循环体代码// 需要 break 语句或其他方式退出
      }

      使用 goto 语句

      start:// 循环体代码// 需要 break 语句或其他方式退出goto start;

      4.3 退出死循环的常见方式

      break 语句

      while (1) {if (exit_condition) {break;  // 退出循环}// 其他代码
      }

      return 语句

      void infinite_loop() {while (1) {if (exit_condition) {return;  // 退出函数}// 其他代码}
      }

      goto 语句

      while (1) {if (exit_condition) {goto exit_loop;  // 跳转到循环外}// 其他代码
      }
      exit_loop:

      4.4 案例:命令行菜单系统

      #include <stdio.h>
      #include <stdlib.h>int main() {int choice;while (1) {printf("\n菜单:\n");printf("1. 选项1\n");printf("2. 选项2\n");printf("3. 退出\n");printf("请选择: ");scanf("%d", &choice);switch (choice) {case 1:printf("执行选项1\n");break;case 2:printf("执行选项2\n");break;case 3:printf("退出程序\n");return 0;  // 退出程序default:printf("无效选择\n");}}
      }

      注意: 

      1. 必须有退出机制
        • 死循环必须提供明确的退出条件(如用户输入、信号触发或逻辑判断),否则程序将无法终止
        • 示例:while (1) { if (user_input == 'q') break; }
      2. 防止逻辑错误
        • 确保循环条件或退出逻辑正确,避免因条件永远为真导致 “真死循环”
        • 错误示例:while (i < 10) { if (i == 5) continue; i++; }(i 停在5)

      5 编程练习

      5.1 水仙花数判断

              编写一个 C 语言程序,该程序直接在 main 函数中实现判断一个整数是否为水仙花数的功能。水仙花数是一个三位数,其各位数字的立方和等于该数本身。例如,153 是一个水仙花数,因为 1^3 + 5^3 + 3^3 = 153。

      #include <stdio.h>int main()
      {int num;      // 存储用户输入的整数int ones;     // 存储个位数字int tens;     // 存储十位数字int hundreds; // 存储百位数字int cubeSum;  // 存储各位数字的立方和// 提示用户输入一个三位数printf("请输入一个整数(三位数):");scanf("%d", &num);// 检查输入的数字是否为三位数(范围:100 到 999)if (num < 100 || num > 999){printf("输入的不是一个三位数。\n");return 1; // 返回非零值表示程序异常退出}// 分解数字为个位、十位和百位ones = num % 10;        // 获取个位数:num 除以 10 的余数tens = (num / 10) % 10; // 获取十位数:num 除以 10 去掉个位后,再除以 10 的余数hundreds = num / 100;   // 获取百位数:num 除以 100 的整数部分// 计算各位数字的立方和cubeSum = ones * ones * ones +            // 个位数的立方tens * tens * tens +            // 十位数的立方hundreds * hundreds * hundreds; // 百位数的立方// 判断是否为水仙花数:立方和是否等于原始数字if (cubeSum == num){printf("%d 是水仙花数。\n", num); // 输出是水仙花数}else{printf("%d 不是水仙花数。\n", num); // 输出不是水仙花数}return 0; // 程序正常退出
      }

              程序在 VS Code 中的多次运行结果如下所示:

      5.2 计算指定年份和月份的天数

              编写一个 C 语言程序,接收用户输入的月份(1-12)和年份,计算并输出该月份在指定年份中的天数。程序需正确处理闰年情况(闰年 2 月 29 天,平年 2 月 28 天)。 

      #include <stdio.h>int main()
      {int month, year; // 存储用户输入的月份和年份printf("请输入月份(1-12):");scanf("%d", &month);printf("请输入年份:");scanf("%d", &year);// 检查月份是否合法(1-12)if (month < 1 || month > 12){printf("输入的月份不合法。\n");return 1; // 非零返回值表示异常结束}// 初始化天数,默认为 31 天(1、3、5、7、8、10、12 月)int days = 31;// 根据月份调整天数switch (month){case 2: // 2 月:判断是否为闰年if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){days = 29; // 闰年 2 月 29 天}else{days = 28; // 平年 2 月 28 天}break;case 4:case 6:case 9:case 11:days = 30; // 4、6、9、11 月为 30 天break;// 其他月份(1、3、5、7、8、10、12 月)保持默认的 31 天}// 输出结果printf("%d年%d月有%d天。\n", year, month, days);return 0; // 程序正常结束
      }

              程序在 VS Code 中的多次运行结果如下所示:

      5.3 打印 1000 年到 9999 年之间的所有闰年 

              编写一个 C 语言程序,分别使用 for 循环、while 循环和 do-while 循环遍历 1000 年到 9999 年的所有年份,判断并打印闰年。闰年规则:能被 4 整除但不能被 100 整除,或能被 400 整除。将三种循环的实现合并到一个程序中,并优化输出格式(每 10 个年份换行)。

      #include <stdio.h>int main()
      {printf("使用 for 循环打印闰年:\n");int count = 0; // 计数器,每打印 10 个年份换行// 使用 for 循环遍历 1000 年到 9999 年for (int year = 1000; year <= 9999; year++){// 判断是否为闰年if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){printf("%d\t", year); // 打印闰年count++;// 每打印 10 个年份换行if (count % 10 == 0){printf("\n");}}}printf("\n\n使用 while 循环打印闰年:\n");count = 0;       // 重置计数器int year = 1000; // 初始化年份为 1000// 使用 while 循环遍历 1000 年到 9999 年while (year <= 9999){// 判断是否为闰年if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){printf("%d\t", year); // 打印闰年count++;// 每打印 10 个年份换行if (count % 10 == 0){printf("\n");}}year++; // 年份递增}printf("\n\n使用 do-while 循环打印闰年:\n");count = 0;   // 重置计数器year = 1000; // 重新初始化年份为 1000// 使用 do-while 循环遍历 1000 年到 9999 年do{// 判断是否为闰年if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){printf("%d\t", year); // 打印闰年count++;// 每打印 10 个年份换行if (count % 10 == 0){printf("\n");}}year++; // 年份递增} while (year <= 9999); // 循环条件return 0;
      }

      5.4 正序和逆序打印英文字母

              编写一个 C 语言程序,首先按顺序打印所有小写英文字母(a 到 z),然后以逆序打印所有大写英文字母(Z 到 A)。

      #include <stdio.h>int main()
      {// 打印小写字母 a 到 zprintf("小写字母 a-z:\n");for (char c = 'a'; c <= 'z'; c++){printf("%c ", c); // 打印当前字母并加空格}printf("\n"); // 换行// 打印大写字母 Z 到 Aprintf("大写字母 Z-A:\n");for (char c = 'Z'; c >= 'A'; c--){printf("%c ", c); // 打印当前字母并加空格}printf("\n"); // 换行return 0;
      }

              程序在 VS Code 中的运行结果如下所示:

      5.5 计算交错序列的和

              编写一个 C 语言程序,计算并输出序列 1 - 1/2 + 1/3 - 1/4 + ... + 1/n 的和,其中 n 是一个用户指定的正整数(例如,n = 100)。序列中的每一项的符号交替出现,即第一项为正,第二项为负,第三项为正,以此类推。

      #include <stdio.h>int main()
      {int n;            // 用户指定的正整数 ndouble sum = 0.0; // 用来存储序列的和int sign = 1;     // 用来表示当前的符号,初始化为正(1)// 提示用户输入正整数 nprintf("请输入一个正整数 n:");scanf("%d", &n); // 读取用户输入的 n// 计算交错序列的和for (int i = 1; i <= n; i++){// 将当前项加到总和中,注意将 1 转换为 1.0 以避免整数除法sum += sign * 1.0 / i;// 改变符号,为下一次迭代做准备sign = -sign;}// 输出结果printf("序列 1 - 1/2 + 1/3 - ... + 1/%d 的和为: %f\n", n, sum);return 0;
      }

              程序在 VS Code 中的运行结果如下所示:

      5.6 回文数判断

              编写一个 C 语言程序,输入一个整型数,判断其是否为回文数(Palindrome Number)。回文数是指一个数字无论从左向右读还是从右向左读都一样的数。如果是回文数,输出 yes,否则输出 no。

      #include <stdio.h>int main()
      {int num, reversed = 0, original; // 存储用户输入的数字、反转后的数字和原始数字// 提示用户输入一个整数printf("请输入一个整数:");scanf("%d", &num);original = num; // 保存原始数字,用于后续比较// 反转数字while (num != 0){reversed = reversed * 10 + num % 10; // 将当前数字的个位添加到反转数字中// reversed * 10 是将反转数字向左移动一位// num % 10 是获取当前数字的个位num /= 10; // 去除当前数字的个位}// 判断原始数字是否与反转后的数字相等if (original == reversed){printf("yes\n"); // 是回文数}else{printf("no\n"); // 不是回文数}return 0;
      }

              程序在 VS Code 中的多次运行结果如下所示:

      5.7 计算 n 的阶乘

              编写一个 C 语言程序,利用 for 循环计算用户输入的整数 n 的阶乘(n!),并输出结果。

      #include <stdio.h>int main()
      {int number, factorial = 1; // 存储用户输入的整数和阶乘结果// 提示用户输入一个整数printf("请输入一个整数:");// 读取用户输入的数scanf("%d", &number);// 使用 for 循环计算阶乘// 由于 factorial 初始值为 1,所以循环变量可以从 2 开始for (int i = 2; i <= number; i++){factorial *= i; // 累乘计算阶乘}// 输出结果printf("%d 的阶乘 %d!:%d\n", number, number, factorial);return 0;
      }

              程序在 VS Code 中的多次运行结果如下所示:

      5.8 货币换零钱组合问题

              某人想将一张面值 100 元的货币换成 10 元、5 元、2 元和 1 元面值的票子,要求换正好 40 张,并且每种票子至少各有一张。编写一个 C 语言程序,计算并输出满足条件的换法总数。

      题目分析:

              为了更高效地解决这个问题,我们需要考虑每种面额纸币的数量范围,并据此设置循环的边界条件。具体地,我们可以这样设定:

      • 10 元纸币:由于至少要有 1 张,且最多不能超过 9 张(否则总金额会超过 100 元),所以循环范围从 1 到 9。
      • 5 元纸币:在剩余金额和剩余张数(40 减去已选的10元纸币数量)的限制下,最多可以选取(100 - 10*已选10元数 - 2 - 1) / 5 张,但至少要有 1 张,所以循环范围需要根据已选的 10 元纸币数量动态计算。
      • 2 元纸币:同样地,其数量也需要在剩余金额和剩余张数的限制下确定,但至少要有 1 张。
      • 1 元纸币:最后,剩余的张数和金额将全部用于 1 元纸币,但也需要至少 1 张。
      #include <stdio.h>int main()
      {int count = 0; // 计数器,记录符合条件的组合数// 遍历 10 元纸币的可能数量(1 到 9张)for (int ten = 1; ten <= 9; ten++){// 遍历 5 元纸币的可能数量(至少 1 张,最多不超过剩余金额和张数限制)// (100 - 10 * ten - 2 - 1) / 5 表示最多可以使用的 5 元纸币数量// 这里减去 2 是因为至少需要留出 1 张 2 元纸币和 1 张 1 元纸币for (int five = 1; five <= (100 - 10 * ten - 2 - 1) / 5; five++){// 遍历 2 元纸币的可能数量(至少 1 张,最多不超过剩余金额和张数限制)// (100 - 10 * ten - 5 * five - 1) / 2 表示最多可以使用的 2 元纸币数量// 这里减去 1 是因为至少需要留出 1 张 1 元纸币for (int two = 1; two <= (100 - 10 * ten - 5 * five - 1) / 2; two++){// 计算 1 元纸币的数量int one = 40 - ten - five - two;// 检查 1 元纸币数量是否合法(至少 1 张,且金额正确)if (one >= 1 && (10 * ten + 5 * five + 2 * two + one) == 100){count++;printf("组合 %d: 10元x%d, 5元x%d, 2元x%d, 1元x%d\n",count, ten, five, two, one);}}}}printf("总共有 %d 种符合条件的换法\n", count); // 34return 0;
      }

              程序在 VS Code 中的运行结果如下所示:

              我们也可以用数学方法来解决这个问题,减少循环次数:

      设:

      • 10 元数量为 x
      • 5 元数量为 y
      • 2 元数量为 z
      • 1 元数量为 w

      则有:

      1. 10x + 5y + 2z + w = 100
      2. x + y + z + w = 40
      3. x, y, z, w ≥ 1

      由方程 2 可得:w = 40 - x - y - z ,代入方程 1:

      10x + 5y + 2z + (40 - x - y - z) = 100
      => 9x + 4y + z = 60

      现在我们需要找到满足:

      • x ∈ [1,9]
      • y ∈ [1, (60-9x-1)/4] (因为 z ≥ 1)
      • z = 60 - 9x - 4y 且 z ≥ 1
      #include <stdio.h>int main()
      {int count = 0; // 初始化计数器,用于记录符合条件的组合数// 遍历 10 元纸币的可能数量(x 的取值范围是 1 到 9,因为至少 1 张,最多 9 张)for (int x = 1; x <= 9; x++){// 计算 5 元纸币的最大可能数量// 根据方程:9x + 4y + z = 60,且 z ≥ 1// 所以y的最大值为:(60 - 9x - 1) / 4for (int y = 1; y <= (60 - 9 * x - 1) / 4; y++){// 计算 2 元纸币的数量 z// 根据方程:z = 60 - 9x - 4yint z = 60 - 9 * x - 4 * y;// 检查 z 是否合法(至少 1 张)if (z >= 1){// 计算 1 元纸币的数量 w// 根据总张数方程:x + y + z + w = 40// 所以 w = 40 - x - y - zint w = 40 - x - y - z;// 检查 w 是否合法(至少 1 张)if (w >= 1){// 如果所有条件都满足,增加计数器并打印当前组合count++;printf("组合 %d: 10元x%d, 5元x%d, 2元x%d, 1元x%d\n",count, x, y, z, w);}}}}// 打印符合条件的组合总数printf("总共有 %d 种符合条件的换法\n", count);return 0;
      }

      相关文章:

    • 支持单双及四像素模式的testpattern仿真
    • [DS]使用 Python 库中自带的数据集来实现上述 50 个数据分析和数据可视化程序的示例代码
    • 如何用,向量表示3维空间种的有向线段(4,2,3)
    • md650透传
    • Day36打卡 @浙大疏锦行
    • 【RocketMQ 生产者和消费者】- 生产者发送故障延时策略
    • QListWidget的函数,信号介绍
    • 前端垫片chimp
    • idea和cursor快速切换
    • 【八股战神篇】操作系统高频面试题
    • 动态导入与代码分割实战
    • 【时时三省】Python 语言----牛客网刷题笔记
    • Spring | 在Spring中使用@Resource注入List类型的Bean并按优先级排序
    • Windows鼠标掉帧测试与修复
    • vue2项目搭建
    • 计算机视觉应用 Slot Attention
    • JVM 的垃圾回收机制
    • 二叉树层序遍历9
    • 输入共模电压范围(Vcm) 和 差分输入电压范围(Vdiff)
    • Linux驱动学习笔记(九)
    • wordpress做旅游网站/域名注册 阿里云
    • 济南网站建设推广服务/关于进一步优化落实疫情防控措施
    • 深圳php网站建设/系统优化大师官方下载
    • 沧州网站建设公司电话/营销模式有几种
    • 婚纱摄影网站seo方案/软文网
    • 凡科网站做的好不好/百度seo怎么样优化