题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1479
题目大意:
``Kronecker's Knumbers''是一家生产塑料数字的小公司,用于标牌(剧院帐篷,加油站价格显示等)。所有者和唯一员工Klyde Kronecker通过维护库存书记录他所使用的每种类型的数字。例如,如果他刚刚做了一个包含电话号码“5553141”的标志,他就会在他的书的一栏中写下“5553141”这个号码,在下一栏中他会列出多少他使用的每个数字:两个1,一个3,一个4和三个5。 (未使用的数字不会出现在清单中。)他以浓缩形式编写库存,如下所示:``21131435''。
前几天,Klyde填写了订单号31123314,并惊讶地发现这个号码的库存与号码相同 - 它有三个1,一个2,三个3和一个4!他称这是一个“自我盘点号码”的例子,现在他想知道哪些号码是自我盘点的,或者通过下面描述的盘点操作的迭代应用导致自我盘点号码。你被雇用来帮助他进行调查。
给定任何非负整数n,其库存是另一个整数,由整数c1d1c2d2 ... ckdk连接组成,其中每个ci和di是无符号整数,每个ci为正,di满足0 <= d1 <d2 < ... <dk <= 9,并且,对于出现在n中任何位置的每个数字d,对于某些i,d等于di,并且在n的十进制表示中恰好出现c次。例如,要计算5553141的库存,我们设置c1 = 2,d1 = 1,c2 = 1,d2 = 3等,给出21131435.数字1000000000000有库存12011(“十二0,一个1”) 。
如果n等于其库存,则整数n称为自库存。如果j是最小数字,则j步骤(j> = 1)之后称为自动清点,使得库存函数的第j次迭代应用的值是自我清点的。例如,21221314在2步后自动盘点,因为21221314的库存为31321314,库存31321314为31123314,而31123314为自库存。
最后,如果k是最小数,则n进入长度为k(k> = 2)的库存循环,使得对于某些整数j(j> = 0),库存函数的第j次迭代应用的值是与第(j+k)次迭代应用的值相同。例如,314213241519进入长度为2的库存循环,因为314213241519的库存为412223241519,而库存412223241519为原始编号314213241519(在这种情况下我们有j = 0)。
编写一个程序,读取一系列非负整数,并为每个输入值,说明它是自动库存,j步后的自动库存,进入长度为k的库存循环,还是没有这些属性。
思路分析:
题目描述有些长,看下来有点费劲。看懂之后发现这就是一个简单的模拟题,对于输入的数字,统计其中0~9各有多少个,形成数字个数+当前数字的组合,就是所求的下一个数字。
注意事项:
input中提示输入数字的位数最多到80位,所以不能直接用atoi()函数进行字符串与数字的转化,需要用字符串存储。另外,输出中存在着一种情况,当循环超过15次时,还未找到规律,就不再向下计算。所以直接将15次计算结果打印出来会比循环一次就判断一次的正确率高。
一些小小的心得:
刚开始读题的时候,理解错了题意,以为每一次循环生成的数字只需要与最开始输入的数字和它的上一次结果进行比较,跑一次出来之后发现最后两组样例输出结果不正确。再仔细读题之后发现要将生成的结果和之前的每一次结果都要进行比较。emmm····· 看的时候看了很久····
这题后台数据有点硬,wa了很多次,前前后后试了20多组输入才AC.建议在写的时候把生成的15组数据都输出来进行对比,还要注意边界样例的选择:只有1位数的时候,所有数字都相等的时候······一定要记得比较一下两次结果数字的长度大小,就是被这个坑了······
上代码(有点小长,希望大佬多多指点):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
char num[105][100];
char st[100];
int main()
{
int count[15];
while(~scanf("%s",st))
{
if(st[0]=='-')
break;
memset(num,0,sizeof(num));
int len1=strlen(st),step=1;
for(int i=0;i<len1;i++)
num[0][i]=st[i];
while(step<=16)
{
memset(count,0,sizeof(count));
int len2=strlen(num[step-1]),j=0;
for(int i=0;i<len2;i++)
count[num[step-1][i]-'0']++;
for(int i=0;i<10;i++)
{
if(count[i]==0)
continue;
if(count[i]<10)
num[step][j++]=count[i]+'0';
else
{
num[step][j++]=count[i]/10+'0';
num[step][j++]=count[i]%10+'0';
}
num[step][j++]=i+'0';
}
//printf("*%s\n",num[step]);
step++;
}
int sign=1,flag=0;
for(int i=0;i<=15;i++)
{
for(int j=i+1;j<=15;j++)
{
int len3=strlen(num[j]);
int len4=strlen(num[i]);
for(int k=0;k<max(len3,len4);k++)
{
if(num[i][k]!=num[j][k])//第i行和第j行不等
{
sign=0;
break;
}
}
if(sign)//第i行和第j行相等
{
if(j-i==1)//没有间隔
{
if(i==0)//从起点开始
printf("%s is self-inventorying\n",st);
else//不从起点开始
printf("%s is self-inventorying after %d steps\n",st,i);
}
else//有间隔
{
printf("%s enters an inventory loop of length %d\n",st,j-i);
}
flag=1;
break;
}
sign=1;//重置
}
if(flag)
break;
}
if(!flag)
printf("%s can not be classified after 15 iterations\n",st);
}
return 0;
}
最后是本人出错的几组数据及结果: