【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
",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.


 

原文地址:https://www.cnblogs.com/AWCXV/p/7632454.html