Kick Start 2018 Round A:Even Digits——细心寻找边界值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题目简述

题意很简单:将给定的数字中所有位上的奇数变为偶数,每次只能增1或减1,最少需要多少步?

思路

其实就是找到离该数最近的各个位均为偶数的数,因为数轴是向两边无限延伸的,所以这个最近意味着在左右两边最近的数中再选一个近的。剩下的就是如何找到这两个最近的数了。
考虑到需要判断每个位上的奇偶,我们选择string来存放给定数字N,这样循环的长度就从N缩减到了string的长度。同时注意到,只有最左奇数才会影响结果(eg:208<—21x—>220,无论个位上的数字是几都不会改变),因此我们可以只需从左向右遍历string,找到第一个(即最左)奇数进行计算即可。
从下面开始,这道题目的坑才真正浮现。
先是过滤不需要处理的情况,我写下了这行代码

if((s[s.length()-1]-'0')%2!=0)//最末位数字是偶数则N为偶数,不需处理
	fun(....);

Sample测试用例中2018的运行结果竟然是0,原来是这个if没有考虑含有奇数位的偶数,改掉,这部分测试用例通过,但是提交运行得到WA,看来是整个思路存在漏洞。
起初我想这很简单,遇到奇数将它加1减1就可以分别得到它的左右,然后剩下的部分向左是88…8,向右是00…0,但是事实证明这样“想当然”会导致重要边界值的遗漏!!,直到我提交了很多次代码都WA才老老实实的把一些看似简单的信息写下来:0<—1—>2,2<—3—>4,4<—5—>6,6<—7—>8,8<—9—>20。等等,9的右边是20,如果按刚才的想法得出的是10,又产生了新的奇数!那把9的情况单拿出来讨论,仍然WA。
鉴于上述进位导致的新的奇数,我又多考虑了一个情况:…89…,此时8也会导致进位,但由于它是偶数所以上述代码里并没有将它考虑进去。于是我列出了一些组合:89,889,689…得出一个结论,当8和9相连时,要考虑更前面的进位,因此在9的讨论中又分为9前面是8和9前面不是8。于是得到如下代码:

#include<iostream>
#include<string>
#include<algorithm>
#include<math.h>
using namespace std;
void fun(string s,int i)
{
    long long res=0;
    if(s.length()==1&&s[0]%2!=0)
        res=1;
    else
    {
        for(int j=0;j<s.length();j++)
    {
		long long d_l,d_r;
        long long temp=atoi(s.substr(j).c_str());
	    d_l=temp-(s[j]-'0'-1)*pow((double)10,double(s.length()-j-1))-atoi(string(s.length()-j-1,'8').c_str());
		if(s[j]=='9')
		{
			if(j>0&&s[j-1]=='8')
			{
				j--;
				while(j>0&&s[j]=='8')j--;
				d_r=2*pow((double)10,double(s.length()-j))-atoi(s.substr(j).c_str());
			}
			else
				d_r=2*pow((double)10,double(s.length()-j))-temp;
			res=min(d_l,d_r);
			break;
		}
        if((s[j]-'0')%2!=0)
        {
            d_r=(s[j]-'0'+1)*pow((double)10,double(s.length()-j-1))-temp;
            res=min(d_l,d_r);
            break;
        }
    }
    }
    
    cout<<"Case #"<<i<<": "<<res<<endl;
}
int main()
{
    int T;
    cin>>T;
    for(int i=0;i<T;i++)
    {
        string s;
        cin>>s;
        fun(s,i+1);
    }
    return 0;
}

果然,通过了Small Dataset,但是Large Dataset仍旧WA。不过这种情况可以推测程序思路应该是正确的,只是没有考虑到大数据集的边界。拿上限10^16一试,发现结果竟然是0。Debug一下,发现问题出在string到long long的转换上,atoi最大也就是Int,因此发生了溢出。将atoi改为strtoll后仍然WA,当我debug 9999 9999 9999 9999 这个边界值时,发现中间结果莫名其妙的出错了,原来是pow()函数返回值为double,直接把这个结果放在一堆long long的数里进行计算,忽略了double的精度丢失。于是显示转换为long long,运行正确。
这道题本身很简单,但是稍微一个细节没注意就会出错,也更加提醒我考虑要周全,找到关键的边界值才能及时发现错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值