USACO 循环数 Runaround Numbers
题面
solution
循环数是那些不包括0且没有重复数字的整数,并且游戏规则起点开始,经过每个数字一次(往后数数字游戏)后回到起点的就是循环数。
如果你经过每一个数字一次(数数字游戏)后,没有回到起点, 你的数字不是一个循环数。
因此,很显然循环数必定在[M,987654321]范围内
code
送上AC代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
bool arr[10];
bool exist[10]; //用于记录1,2,3...这些数字在整数num中的存在情况
unsigned int num,cnt;
int cycle[10];
int main()
{
int k,len;
int pos;
scanf("%d",&num);
while (true)
{
Begin:
memset(arr,0,sizeof(arr));
memset(exist,0,sizeof(exist));
num++; //从输入的整数下一个数字开始判断是否为循环数
cnt=0;
k=1;
len=0; //len,记录num的位数
while (k<=num)
{
k=k*10;
len++;
}
len--;
k=num;
for(pos=len;pos>=0;pos--)
{
if (exist[k%10]||!(k%10)) //num中存在重复的数字或者0,必定不是循环数,继续判断下一个数,goto Begin
goto Begin;
cycle[pos]=k%10; //cycle[]中记录着,num中的pos位置,要往下数k%10个数字
exist[k%10]=true; //标记数字k%10已经在num中存在
k=k/10; //对于整数num是从后往前一次剥离每一位数字,在得到当前位数字后,前一位数字应为(k/10)%10
}
pos=0;
//循环数,往后数数字循环游戏过程,最开始从num的第一个数字往后数数,pos=0
while (!arr[pos]) //根据规则要求经历每个位置有且仅有一次最终回到起始位置才是循环数,判断当前位pos是否已经经历过?
{
arr[pos]=true; //标识整数num当前位置已经被数过(经历过)
pos=(pos+cycle[pos])%(len+1); //计算下一轮数数字游戏,起始位置
cnt++; //游戏每数过一个位置上的数字,游戏轮数,计数cnt++
}
if (cnt==len+1&&pos==0) //从起始位置开始,判断游戏的轮数是否和整数num的位数相同且最终位置回到了起始位置0
{ //由于前面计算得到整数num的位数len后,由于数组arr[]从0开始,有一个len--操作,因此这里比较为cnt==len+1
printf("%d",num);
return 0;
}
}
return 0;
}