洛谷P1662题:环形报数游戏与方向反转策略详解
一、问题分析
题目要求模拟1337人围成一圈的报数游戏,规则如下:
从1号开始正向报数(1,2,3...)
当报的数字包含7或是7的倍数时,报数方向立即反转
报数到第X个数字时,输出当前报数人的编号
二、完整代码
#include <iostream> using namespace std; // 检查数字是否包含7或者是7的倍数 bool containsSeven(int num) { // 检查是否是7的倍数 if (num % 7 == 0) return true; // 逐位检查数字是否包含7 while (num > 0) { if (num % 10 == 7) // 检查当前位是否为7 return true; num /= 10; // 移除已检查的最低位 } return false; } int main() { int X; // 要报数的总次数 cin >> X; // 输入X const int N = 1337; // 总人数 int current = 1; // 当前报数人的编号(初始为1号) int direction = 1; // 报数方向:1表示正向,-1表示反向 // 模拟报数过程,从1报到X for (int num = 1; num <= X; ++num) { // 如果当前数字包含7或是7的倍数,反转方向 if (containsSeven(num)) { direction *= -1; // 反转方向(1变-1,-1变1) } // 移动到下一个人(最后一个数字不需要移动) if (num < X) { current += direction; // 根据方向移动到相邻位置 // 处理环形边界(超过最大值时回到1) if (current > N) current = 1; // 处理环形边界(小于最小值时回到1337) if (current < 1) current = N; } } // 输出最终报数人的编号 cout << current << endl; return 0; }
三、算法解析
1. 数字特性检查函数
bool containsSeven(int num) { if (num % 7 == 0) return true; // 7的倍数检查 while (num > 0) { if (num % 10 == 7) return true; // 逐位检查数字7 num /= 10; // 数字右移 } return false; }
数学特性利用:
num % 7 == 0
判断7的倍数逐位分解:通过循环
num % 10
和num /= 10
检查每一位数字复杂度:O(log n),与数字位数成正比
2. 环形报数模拟
current += direction; // 方向控制移动 // 环形边界处理 if (current > 1337) current = 1; if (current < 1) current = 1337;
方向变量:
direction=1
正向,direction=-1
反向环形处理技巧:
超过1337时回到1(
current = 1
)小于1时回到1337(
current = N
)边界判断:最后一个数字报完不移动
3. 反转触发机制
if (containsSeven(num)) { direction *= -1; // 简洁的方向反转}
即时反转:满足条件时立即改变方向
累积效应:多次触发会导致方向连续反转
四、常见错误
边界处理错误:未考虑环形边界导致的越界
反转时机错误:在移动后检查数字特性
包含7判断错误:漏掉数字中间或结尾的7
最后一个数字处理:报完最后一个数字后不应移动
方向变量初始化:初始方向应为正方向(1)
原创内容 转载请注明出处