USACO-Section2.2 Runaround Numbers【暴力枚举】

来源:互联网 发布:开淘宝网店的流程 编辑:程序博客网 时间:2024/06/05 07:02

题目描述:

循环数是这样的整数:它包含的数字都是独特不相同的,(如1111就是不正确的),而且没有0,例如81362。它有一个有趣的性质:
1.从左端开始,当前的数是多少就往右数几位(首尾相接,即认为最右边的数字之后是左边第一个数),对于81362,你将会停在一个新数字6上
2.重复上述过程,这回数6个数字因为刚刚停在6上。你将会停在2上
3.继续,(数2个数字),停在1
4.继续,(数1个数字),停在3
5.停在8,这个时候你已经接触了每个数字一次且仅一次。如果不是这样,那就不是循环数。
给定一个数M,找到并输出刚好比M大的下个循环数。使用unsigned long存储M。(翻译来源:NOCOW)

INPUT FORMAT:

(file runround.in)
仅仅一行, 包括M

OUTPUT FORMAT:

(file runround.out)
仅仅一行,输出第一个比M大的循环数。


SAMPLE INPUT

81361


SAMPLE OUTPUT

81362


解题思路:

这道题直接枚举就可以计算出来,主要注意条件的筛选,还有通过数字不重复剪枝。

#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>unsigned long n;int a[10],vnum[10],v[10],count=0;//a数组倒序保存初始数字,vnum标记往后推之后的位置,v标记已用的数字,count标记初始数字的位数 int temp(int p){//返回倒着数应该到的位置     int q=p-a[p]%count;    if(q<0)q=count+q;    return q;}int judge(){//判断     int i;      for(i=9;i>=0;i--){//初始化标记数组         v[i]=0;        vnum[i]=0;    }    for(i=count-1;i>=0;i--){         if(v[a[i]]>0||a[i]==0)return 0;//如果数字用过或者数字为0则直接返回         v[a[i]]=1;         vnum[temp(i)]++;    }    for(i=0;i<count;i++)//根据题目描述,所有数字后推之后恰好围成一个环,如果提前有环则返回         if(vnum[i]>1){        return 0;           }        int t=count-1;        for(i=0;i<count-1;i++){            if(temp(t)==count-1)return 0;            t=temp(t);        }    return 1;}int main(){    FILE *fin  = fopen ("runround.in", "r");    FILE *fout = fopen ("runround.out", "w");    fscanf(fin,"%lu",&n);    int i;    n++;    while(n){//保存每一位数字         a[count++]=n%10;        n=n/10;    }    while(!judge()){        a[0]++;    for(i=0;i<count;i++)//倒序方便处理数字进位的情况         if(a[i]>=10){            a[i+1]++;            a[i]=1;            if(i==count-1)count++;          }       }    for(i=count-1;i>0;i--)    fprintf(fout,"%d",a[i]);    fprintf(fout,"%d\n",a[i]);    exit(0);}