hdu - 3925 - Substring(枚举匹配)

题意:给两个整数a、b,问a最少加上多少后,b成为a的子串。( 0 <= a <= 10^100, 0 <= b <= 10^7)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3925

——>>开始用C++<string>库中的find来找子串,结果TLE了,后来,枚举匹配位:

13464164643467464646   1836,

             | | | |                   | | | |

             | | | |                  1836

            1836

使4646变成1836,那么需要+ (11836 - 4646);(1836不够大,在前面补1,后面补0,这个数据刚刚好是最后一个位置,不用补0)

使1646变成1836,那么需要+ (18360000000000 -164643467464646 );(1836够大,后面补0就行)

但是上面的运算都是用字符串来运算的,而不是直接用 + - ;

从4开始,一直枚举到最左边的1;

WA,WA,WA……多少次,太痛苦了……

最后,发现我的程序测试几个40多位的a,7位的b都是正确的,有点意思了,再测,测,测……终于发现:当a长度比b的长度小时,没做处理,修改——>AC!

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 100 + 10;

bool cmp(char *s, int high, int low, char *sub)     //判断s[high]~s[low]是否就是字符串sub
{
    int j = 0;
    for(int i = high; i <= low; i++) if(s[i] != sub[j++]) return 0;
    return 1;
}
int cmpp(char *a, char *b)      //字符数组表示的a与b的大小比较
{
    int len_a = strlen(a), len_b = strlen(b), len = min(len_a, len_b), i;
    if(len_a != len_b)      //在程序除去了前导0,这里可直接比较位数来确定谁大谁小
    {
        if(len_a > len_b) return 1;
        else return -1;
    }
    else        //位数相等时
    {
        for(i = 0; i < len; i++)
        {
            if(a[i] > b[i]) return 1;       //数a > b
            if(a[i] < b[i]) return -1;      //数a < b
        }
        return 0;       //如果上面没返回,那么a == b
    }
}
int to_int(char *s, int high, int low)      //将字符数组s转换成整数
{
    int ret = 0;
    for(int i = high; i <= low; i++) ret = ret*10 + s[i]-'0';
    return ret;
}
int main()
{
    int i, j, k, u, v, cnt = 1, T;
    char a[maxn], b[maxn], B[maxn], c[maxn], minn[maxn];        //a, b为输入数组,B, c为过程中处理的中间数组,minn存最小值(结果)
    scanf("%d", &T);
    while(T--)
    {
        scanf("%s%s", a, b);
        int len_a = strlen(a), len_b = strlen(b);
        for(i = 0; i < maxn; i++) minn[i] = '9';        //初始化为最大
        for(i = len_b; i < maxn; i++) b[i] = '0'; b[maxn-1] = 0;        //为b后面赋0,下面减法用到
        int bb = to_int(b, 0, len_b-1);     //求b的值
        if(len_a < len_b)       //当子串长度比原串更长时,子串更大
        {
            int aa = to_int(a, 0, len_a-1);
            printf("Case #%d: %d\n", cnt++, bb-aa);
            continue;
        }
        bool ok = 0;        //匹配成功标志
        for(i = len_a-len_b; i >= 0; i--)       //从后往前一一模拟
        {
            int aa = to_int(a, i, i+len_b-1);
            if(aa == bb)        //剪枝,匹配成功时
            {
                ok = 1;
                break;
            }
            else        //匹配不成功时
            {
                for(u = 0; u < maxn; u++) B[u] = b[u];      //取一个b到B,不能直接操作原数组!
                for(j = len_a-1, k = len_a-1-i; j >= i; j--, k--)
                {
                    if(B[k] >= a[j]) c[k] = B[k] - a[j] + '0';
                    else        //借位
                    {
                        if(k-1 >= 0) B[k-1]--;
                        c[k] = B[k] + 10 - a[j] + '0';
                    }
                }
                c[len_a-i] = 0;     //设结束字符
                for(v = 0; v < len_a-i; v++) if(c[v] != '0') break;     //除去前导0
                if(v != 0) for(u = 0; v <= len_a-i; u++,v++) c[u] = c[v];
                if(cmpp(c, minn) < 0) for(u = 0; u <= len_a-i; u++) minn[u] = c[u];     //更新
            }
        }
        if(ok) printf("Case #%d: %d\n", cnt++, 0);
        else        //还要1次对“-1”位的模拟
        {
            for(u = 0; u < maxn; u++) B[u] = b[u];      //取一个b到B,不能直接操作原数组!
            for(j = len_a-1, k = len_a; j >= 0; j--, k--)
            {
                if(B[k] >= a[j]) c[k] = B[k] - a[j] + '0';
                else        //借位
                {
                    B[k-1]--;
                    c[k] = B[k] + 10 - a[j] + '0';
                }
            }
            c[0] = B[0];        //存下第1位
            c[len_a+1] = 0;     //设结束字符
            for(v = 0; v < len_a+1; v++) if(c[v] != '0') break;     //除去前导0
            if(v != 0) for(u = 0; v <= len_a+1; u++,v++) c[u] = c[v];
            if(cmpp(c, minn) == -1) for(u = 0; u <= len_a+1; u++) minn[u] = c[u];       //更新
            printf("Case #%d: %s\n", cnt++, minn);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值