“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话。
输入格式:
输入在一行中给出出生年份y和目标年份中不同数字的个数n,其中y在[1, 3000]之间,n可以是2、或3、或4。注意不足4位的年份要在前面补零,例如公元1年被认为是0001年,有2个不同的数字0和1。
输出格式:
根据输入,输出x和能达到要求的年份。数字间以1个空格分隔,行首尾不得有多余空格。年份要按4位输出。注意:所谓“n个数字都不相同”是指不同的数字正好是n个。如“2013”被视为满足“4位数字都不同”的条件,但不被视为满足2位或3位数字不同的条件。
输入样例1:
1988 4
输出样例1:
25 2013
输入样例2:
1 2
输出样例2:
0 0001
本题的难点在于理解“数字不同”这句话,如果理解存在偏差,则分数必不会高,因为一开始的算法策略就错了。本人第一次做此题时,将“数字不同”理解为“当前位上的数字与任意剩余位上的数字都不同”,其实题目中的一个细节已经可以推翻这个结论——“公元1年被认为是0001年,有2个不同的数字0和1”,也就是说,在四个数字0001中,0和1是不同的,故不同的数字数量为2,而不去管某一位上的0与其他位上的0重复而不将0视为"数字不同",即,我们从0001中剔除了重复的0,得到0和1,这样的过程,如果敏锐一点,会发现就是将数字加入集合的过程。
我们知道集合中的元素是不会重复的,故结合本题,可设一数组,下标为各个位上的数字,每一元素为0或1,0表示当前位的数字还没有加入集合,1表示当前位上的数字已经加入集合,故可通过判定数组元素是否为0来决定将数字加入集合的操作,如果元素不为0,说明已经当前数字已经加入集合,不执行,如果元素为0,则将数字加入集合即将元素置1。当然,我们还需要一个计数器来统计有多少数字加入集合,即集合的大小是多少,若集合的大小等于要求的n,则此数字满足条件。其核心算法为:
while(num)
{
int t=num%10;
if(!Set[t])//若当前位上的数字t未加入集合
{
Set[t]=1;//将t加入集合
size++;//集合大小+1
}
num/=10;
}
有了核心算法还不够,我们还需要重新审阅一下题目以查看是否有遗漏的细节。我们注意到:“不足4位的年份要在前面补零”,于是我们需要在输出的时候以4位数字的格式输出,不足补0,右对齐。
分析完核心算法和题目给出的细节,可能还不够,我们需要更为细致,敏锐,分析更加透彻才能把握完整正确的解题方向。于是我们还注意到一个隐藏细节:若数字小于1000,因为题目始终要求的是对4位数字进行判定,所以数字会有前导0,故0必然需要加入集合,其处理算法为:
if(num<1000)//若数字小于1000,则数字中必然存在前导0
{
Set[0]=1;//将0加入集合
size++;//集合大小+1
}
至此,我们已经把握了完整正确的解题方向与核心算法,如果态度仔细,必定能一次性AC,以下是具体代码:
#include
#include
#include
int check(int num, int n)
{
int set[10] = {0};
int size = 0;
if(num < 1000)/*若年份小于1000 则因为是四位的年份 则必有前导0 所以要把0加入集合*/
{
set[0] = 1;
size++;
}
while(num)/*将年份num每一位都不重复的加入集合 以此来确定不同的位数的个数*/
{
int t = num % 10;
if(set[t] == 0)
{
set[t] = 1;
size++;
}
num = num/10;
}
if(size == n)
{
return 1;
}
else
return 0;
}
int main()
{
int num;
int sum;
int i;
int n;
scanf("%d %d", &num, &n);
i = num;
while(check(i, n) == 0)/*用函数来检查当前年份i是否满足条件 不满足则年份加1继续判断*/
{
i++;
}
sum = i - num;
printf("%d %04d\n", sum, i);/*注意输出 不满足四位要用零补齐,右对齐*/
return 0;
}
}
原文:https://blog.csdn.net/qq_37729102/article/details/80825421
注意链接内的使用bool类型函数返回true false 若在pta里用c上交 则出现编译错误 这个好像是c++里的东西
如果熟悉C++STL的同学,可以使用set来进行更为快速地解题,以下是使用set的具体代码:
#include
#include
#include
using namespace std;
int main()
{
int n,num;
sets;
cin>>num>>n;
int i=num-1;
while(s.size()!=n)//若集合大小不为n
{
s.clear();//清空集合,以待填充
int t=++i;//先增i,使i与循环判定状态一致
if(t<1000)
s.insert(0);//若数字小于1000,则数字中必然存在前导0,将0加入集合
while(t)
{
s.insert(t%10);//将每一位上的数字加入集合
t/=10;
}
}
cout<
解题,首先抓住并处理好题目的每一个细节,如果题目的细节理解错了,那么一开始的算法策略是错的,你将无法AC。处理好题目的细节之后,再思考还有哪些隐藏的细节需要你挖掘,比如此题的“前导0”,是对你程序输入输出特性和态度的一种考察,如果你足够细致,你会注意到这点并处理。当你处理完所有细节之后,你还可能需要考虑特殊情况,即输入数据较特殊的时候,你也需要将其列入考虑范围,只有这样,你才能一次性AC。
综上,AC=处理好所有细节+处理好所有可能的特殊情况。