您的位置:首页 > 编程语言 > C语言/C++

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

2017-07-23 13:58 344 查看

题目描述:

循环数是这样的整数:它包含的数字都是独特不相同的,(如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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 usaco runround