【3004】循环数
Time Limit: 3 second
Memory Limit: 2 MB
【问题描述】
“循环数”指那些不包括数字0的没有重复数字的整数(比如81362),并且同时具有一个有趣的性质, 就像 这个例子: 如果你从最左边的数字开始 (在这个例子中是8) 数从左边这个数字到右边 (如果数到了最右边,回 到最左边), 你会停止在另一个新的数字 (如果没有停在一个不同的数字上,这个数就不是循环数)。就像: 8 1 3 6 2 从最左边接下去数8个数字: 1 3 6 2 8 1 3 6 所以下一个数字是6. 重复这样做 (这次从“6”开始数6个数字) 并且你会停止在一个新的数字上: 2 8 1 3 6 2,也就是2. 再这样做 (这次数两个): 8 1; 再一次 (这次一个): 3; 又一次: 6 2 8 这时你回到了起点。 所以81362是循环数。 在从每一个数字开始数1次之后.如果你在从每一个数字开始数一次以后没有回到起点,你的数字不是一个循环数。 给你一个数字 M (在1到9位之间), 找出第一个比 M大的循环数, 并且一定能用一个无符号长整形数装下。
【输入】
仅仅一行, M 的值
【输出】
仅仅一行,第一个比M大的循环数
【输入样例】
81361
【输出样例】
81362
【题解】
有更好的解法。但是我直接暴力模拟了。在代码里面说吧,太恶心了。有点复杂;
【代码】
#include <cstdio> #include <iostream> #include <string> using namespace std; string s1; bool bo[1000]; int pret; void input_data() { cin >> s1; } void get_ans() { bool flag = false; //flag函数用于判断循环的出口 int l = s1.size(); //获取数字的长度 int t = 0; for (int i = 0;i <= l-1;i++) //先把输入的字符串转成整形数字 t = t*10 + s1[i] - '0'; pret = t; //pret是最初输入的数字 int rest = l; while (!flag) { bool ok = true; //ok用于判断 有0 ,有重复数字的情况 for (int i = 0;i <= l-1;i++) //判断是否有0 if (s1[i] == '0') { ok = false; break; } for (int i = 1;i <= 9;i++) bo[i] = false; for (int i = 0;i <= l-1;i++) //用于判断是否有重复的数字 if (!bo[s1[i]-'0']) bo[s1[i]-'0'] = true; else { ok = false; break; } if (ok) //如果以上情况都未出现就试试这个数是否为循环数 也还好 才40行左右 { int j = 0; //j表示现在到数字各个数字的指针 int k = s1[0] - '0'; //k表示接下来要走几步 for (int i = 0;i <= l-1;i++) //用于判断是否到了之前已经走过的地方 bo[i] = true; bo[j] = false; //初始位置已经走过了 rest --;//rest用于记录剩余的数字 flag = true; for (int mm = 1;mm <= l;mm++) //表示要检验的次数 ,检验l-1次时所有数字都被走过,当走第l次时,检验能否回到原点。 { for (int i = 1;i <= k;i++) //先跳k步 { j++; if (j > (l-1)) j = 0; } if (!bo[j] && rest!=0) //如果遇到了之前跳到的数字,就判断一下是否已经没有剩余数字 { flag = false; break; } if (!bo[j] && j!=0) //又或者回到了第一次扫描的位置 { flag = false; break; } bo[j] = false; //如果这个数字之前没出现过 现在就标记下 rest--; //剩余的数字递减 k = s1[j] - '0'; //获取下一个需要循环的次数 } if (t == pret) flag = false; //因为是大于输入的数字 所以不能和输入数字相同 if (flag == true) //如果以上约束都过了 就可以了 输出就好 { printf("%d\n",t); return; } } t++; //尝试下一个数字 直接递增 string ts; int ll = 0; int tt = t; while (tt > 0) //tt用于把数字转化成string类 存在ts字符串中。 { ts[++ll] = (tt % 10) + '0'; tt = tt / 10; } for (int i = ll;i >= 1;i--)//这样存是倒序的,所以再把它正序下。 s1[ll-i] = ts[i]; rest = ll; //更新剩下的数字 l = ll;//更新数字的长度 } } int main() { input_data(); get_ans(); return 0; }
【代码2更优秀的解法,pascal版】
这个程序直接用数组记录某个数是否可以由其他数字i通过走a[i]步走到。如果所有的位置都能通过其他位置通过走x步到,那就是一个循环数。要注意死循环的情况排除掉,比如12
1->2 ,但是2 会一直到2,不能到1.这种情况要排除。
var n:longint; a,b:array[1..100] of integer; function yes:boolean; var s:string;l,i:integer; begin str(n,s); if pos('0',s)>0 then exit(false); l:=length(s); for i:=1 to l do val(s[i],a[i]); fillchar(b,sizeof(b),0); for i:=1 to l do begin inc(b[a[i]]); if b[a[i]]>1 then exit(false); end; fillchar(b,sizeof(b),0); for i:=1 to l do begin if (i+a[i]-1)mod l+1=i then exit(false); inc(b[(i+a[i]-1)mod l+1]); end; for i:=1 to l do if b[i]=0 then exit(false); yes:=true; end; begin readln(n); inc(n); while not yes and (n<maxlongint) do inc(n); writeln(n); end.