USACO:2.2.3 Runaround Numbers 循环数

来源:互联网 发布:monaco 字体 windows 编辑:程序博客网 时间:2024/06/10 00:17

USACO:2.2.3 Runaround Numbers 循环数

题目描述

★Runaround Numbers 循环数

循环数是那些不包括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 这是你回到了起点, 在从每一个数字开始数1 次之后. 如果你在从每一个数字开始数一次以后没有回到起点, 你的数字不是一个循环数.
给你一个数字 M (在1 到9 位之间), 找出第一个比 M 大的循环数, 并且一定能用一个无符号长整形数装下.
PROGRAM NAME: runround
INPUT FORMAT
仅仅一行, 包括M
SAMPLE INPUT (file runround.in)
81361
OUTPUT FORMAT
仅仅一行,包括第一个比M 大的循环数.
SAMPLE OUTPUT (file runround.out)

81362

解题思路

       首先我们一定要仔细阅读题目,理解题意。从开始数往后进行枚举,循环数是那些不包括0 这个数字的没有重复数字的整数,剔除不满足条件的,然后判断其是不是runround number,如果是就输出退出。还有一些细节处理。

下面是源代码:

//我的解#include <iostream>#include<string.h>#include<cstdio>using namespace std;int M;int vis[9+1];int flag=1;int rst;void isrunaround(int x){char str1[10];int vv[10],i,j,len,next_k,k=0,cnt=0;;memset(vv,0,10*4);sprintf(str1,"%d",x);//数字输出到字符串sscanf用法len=strlen(str1);for (i=0;i<len;i++){vv[str1[i]-48]=vv[str1[i]-48]+1;//0-9每位数个数计数,单字符与数字相差的是48if (vv[0]==1||vv[str1[i]-48]==2) return;//循环数不包括0,没有重复数字的整数}for (;;){if(cnt==len){//是循环数,遍历了每个数字flag=0;//成功找到rst =x;//记录结果return;}j=str1[k]-48;vis[k]=1;//访问过next_k=(k+j)%len;//下一个数的位置if (vis[next_k]==1&&next_k!=0) return;//访问过且不是回到了起点k=next_k;cnt++;}}int main(){freopen("runround.in","r",stdin);//freopen("runround.out","w",stdout);cin>>M;int i;for(i=M+1;flag;i++){memset(vis,0,10*4);vis[i]=1;isrunaround(i);}cout<<rst<<endl;return 0;}//官方原解//The trick to this problem is noticing that since runaround numbers must have unique digits, they must be at most 9 digits long. There are only 9! = 3628//80 nine-digit numbers with unique digits, so there are fewer than 9*362880 numbers with up to 9 unique digits. Further, they are easy to generate, so we//generate all of them in increasing order, test to see if they are runaround, and then take the first one bigger than our input.#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>int m;FILE *fout;/* check if s is a runaround number;  mark where we've been by writing 'X' */intisrunaround(char *s){    int oi, i, j, len;    char t[10];    strcpy(t, s);    len = strlen(t);    i=0;    while(t[i] != 'X') {oi = i;i = (i + t[i]-'0') % len;//计算下一个数,进行遍历操作t[oi] = 'X';    }    /* if the string is all X's and we ended at 0, it's a runaround */    if(i != 0)//没有回到原点return 0;    for(j=0; j<len; j++)if(t[j] != 'X')//没有遍历所有的数位    return 0;    return 1;}/* * create an md-digit number in the string s. * the used array keeps track of which digits are already taken. * s already has nd digits. */voidpermutation(char *s, int *used, int nd, int md)//1-9产生md位数的排列,{    int i;    if(nd == md) {s[nd] = '\0';if(atoi(s) > m && isrunaround(s)) {    fprintf(fout, "%s\n", s);    exit(0);}return;    }    for(i=1; i<=9; i++) {if(!used[i]) {    s[nd] = i+'0';//数字转化为字符    used[i] = 1; //递归式枚举,保证不重复。    permutation(s, used, nd+1, md);    used[i] = 0;}    }}voidmain(void){    FILE *fin;    char s[10];    int i, used[10];    fin = fopen("runround.in", "r");    fout = fopen("runround.out", "w");    assert(fin != NULL && fout != NULL);    fscanf(fin, "%d", &m);    for(i=0; i<10; i++)used[i] = 0;    for(i=1; i<=9; i++)permutation(s, used, 0, i);    assert(0);/* not reached */}

由于自身是初学者,编程能力有限,未达到专业程序员的水平,可能误导大家,请大家甄读;文字编辑也一般,文中可能会有措辞不当。博文中的错误和不足敬请读者批评指正。

部分引自  http://pingce.ayyz.cn:9000/usaco/20110129214306/subset_001.html


0 0