题目链接:http://poj.org/problem?id=1016
这是我有史以来改过最久的一道题,一道模拟题,题目很简单 但是让我WA住的地方很傻比。。。长个记性吧。我服了
题目大意:
现在有一个规则,给定一个数,统计其中数字(0~9)出现的次数,然后从小到大重新组成一个数。如112233,其中1出现2次,2出现2次,3出现2次,那么新的数为212223.现在有一个位数至多为80位的数,通过变换后根据题目中给定的输出的规定进行输出。
1.n is self-inventorying
2.n is self-inventorying after j steps
3.n enters an inventory loop of length k
4.n can not be classified after 15 iterations
如果一个数变换一次过后仍为本身按1输出,如果不为本身,但是经过n(n<=15)次变换后为原来的数,则按2输出,如果超过15次仍未出现,但是在这15次变换中有数是相同的,求出这个相同两个数的最小长度,然后按3输出,最后若15次变换内没有出现上述每一种条件,则按4输出。需要注意的是先要执行上面的情况后才能考虑下面的情况。
分析:
模拟过程即可。
下面是我的代码:
#include <iostream>
#include<cstring>
#include<string>
#include<map>
#include<cstdio>
#include<cstdlib>
using namespace std;
int main()
{
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
string s;
while(cin>>s)
{
// cout<<"ssssssssss"<<s<<endl;
//cout<<9+'0'<<endl;
if(s=="-1") break;
map<int,int> mp;
for(int i=0;i<=9;i++)
mp[i]=0;
int len=s.size();
for(int i=0;i<len;i++)
{
mp[s[i]-'0']++;
}
// cout<<mp[9]<<endl;
// int flag=1;
// for(int i=0;i<=9;i++)
// {
// if(mp[i]>80) 根本不用判断什么大于不大于80位!
// {flag=0;break;}
// }
cout<<mp[9]<<endl;
// if(flag==0) { cout<<s<<" can not be classified after 15 iterations"<<endl; continue;}
int kase=0;
int T=0;
string a[20];
a[0]=s;
int t=0;
string s1=s;
int xiabiao=0;
int len2=0;
// if(flag)
// {
while(1)
{
kase++;
if(kase>15) break;
string s2;
for(int i=0;i<=9;i++)
{
// if(i==1)
// cout<<"-----"<<mp[1]<<endl;
// cout<<char(10+'0')<<endl;
// cout<<char(9+'0')<<endl;
if(mp[i]!=0)
{
if(mp[i]>9)
{
int num=mp[i];
s2+=num/10+'0';
s2+=num%10+'0';
s2+=i+'0';
}
else{
s2+=mp[i]+'0';
s2+=i+'0';}
}
}
// cout<<"kase="<<kase<<" "<<s2<<endl;
t++;
a[t]=s2;
// cout<<"one "<<kase<<endl;
if(s2==s1) break;
else
{
for(int i=0;i<t;i++)
{
if(a[i]==s2)
{T=1;xiabiao=i;break;}
}
if(T==1) break;
}
// mp.clear();
for(int i=0;i<=9;i++)
mp[i]=0;
s1.clear();
s1=s2;
// cout<<"s1="<<s1<<endl;
len2=s1.size();
for(int i=0;i<len2;i++)
{
mp[s1[i]-'0']++;
}
// for(int i=0;i<=9;i++)
// cout<<mp[i]<<",";
// cout<<endl;
}
// }
// cout<<"kase="<<kase<<endl;
if(kase>15)
cout<<s<<" can not be classified after 15 iterations"<<endl;
else if(kase==1)
cout<<s<<" is self-inventorying"<<endl;
else
{
if(T)
cout<<s<<" enters an inventory loop of length "<<kase-xiabiao<<endl;
else
cout<<s<<" is self-inventorying after "<<kase-1<<" steps"<<endl;
}
}
return 0;
}
我的代码太乱太长了 实验课的时候写的 后来改的乱七八糟。 一开始是因为数字的个数有可能大于两位数,当大于两位数转换成字符时, 例如 cout<<char(10+'0')<<endl;时,我以为的输出结果是10,而实际上结果是 “:”符号!所以说明这方面我还有漏洞 根本没意识到这个问题 导致我改了这么久 也导致了 边界80的问题。通过这一道题改了这么长时间能看的出我还存在很多方面的问题 尤其是比较基础的细节问题 ,这些问题由于我平时不注意 导致了在比赛或者上课做题的时候一直WA。 以后还是要通过多做题 查缺补漏 。 谭琳老师说的那句话真的很对,犯错才会让你进步的很快,我现在懂了。
下面是网上参考的代码,和我写的差不多,都用到了string,需要向他学习的是 他的代码非常简洁,而且用到了函数(这题确实用函数做会简介很多,因为要多次求下一个的字符串)。而且我感觉也没必要用map 用char也完全解决问题了,用map虽然没有错,但看了别人的发现感觉自己用map多此一举了。。向别人学习吧。
AC代码:传送门
#include<iostream>
#include<string>
using namespace std;
#define maxn 100
string SelfString(string str)
{
int i, a[10]={0};
string s;
for(i=0; i<str.length(); i++)
a[str[i]-'0']++;
for(i=0; i<10; i++)
{
if(a[i])
{
while(a[i])
{
s += a[i]%10+'0';
a[i] /= 10;
}
s += i+'0';
}
}
return s;
}
int main()
{
string str;
while(cin >> str, str != "-1")
{
string a[maxn];
int i, j, k=1, ans=0;
a[0] = str;
for(i=1; i<=15; i++)
{
a[i] = SelfString(a[i-1]);
if(a[i] == a[i-1])
{
ans = 1;
break;
}
for(j=0; j<i; j++)
if(a[i] == a[j])
{
ans = 2;
break;
}
if(j < i)
break;
}
if(ans==1 && i==1)
cout << a[0] <<" is self-inventorying "<<endl;
else if(ans==1)
cout << a[0] <<" is self-inventorying after "<< i-1 <<" steps "<<endl;
else if(i <= 15)
cout << a[0] <<" enters an inventory loop of length " << i-j <<endl;
else
cout << a[0] << " can not be classified after 15 iterations" <<endl;
}
return 0;
}