pku 3373 Changing Digits 爆搜+强剪枝

http://poj.org/problem?id=3373

题目意思:

给出2个整数N(n<10^100)和K(k<10000),求满足以下条件的整数M
1、M与N位数相同
2、M能被K整除
3、满足以上两点时,M和N不同位数最少

4、满足以上三点时,M值最小

思路:

题目意思很好理解,我们只要以n为基础分两个方向搜索即可,

1:首先搜索比n小的,这样保证在为数不同的前提下,M值最小;

2:搜索比n大的,

详细的解题报告:http://blog.csdn.net/lyy289065406/article/details/6698787

解题报告中说只要改变n的5位就一定能够找到解(由鸽巢定理得 k最多为4位),自己没能理解,希望有人能够给解释。

View Code
#include <cstdlib>

#include <iostream>

#include <cstring>

#include <algorithm>

#include <cstdio>

using namespace std;



const int maxn=109;



int rem[maxn][maxn*maxn];

int ans[maxn],num[maxn],mod[maxn][12];

char s[maxn];

int K,len,Mod;



void init()

{

    int i,j;

    memset(rem,0,sizeof(rem));

    //mod[i][j]寸10^i*j%K的值

    for (i = 0; i < 10; ++i) mod[0][i] = i%K;

    for (i  = 1; i < len; ++i)

    {

        for (j = 0; j < 10; ++j)

        mod[i][j] = (mod[i - 1][j]*10)%K;

    }

    //计算s模K的余数,将s倒置

    Mod = 0;

    for (i = 0; i < len; ++i)

    {

        ans[i] = num[i] = s[len - i - 1] -'0';

        Mod += mod[i][num[i]];

        Mod %= K;

    }

}

bool dfs(int left,int pos,int M)

{

    int i,j;

    if (M == 0)//余数为0得到解

    {

        for (i = len - 1; i >= 0; --i) printf("%d",ans[i]);

        printf("\n");

        return true;

    }

    if (left == 0 || rem[left][M] > pos) return false;//关键的剪枝

    //搜索比N小的从高位开始

    for (i = pos; i >= 0; --i)

    {

        for (j = 0; j < num[i]; ++j)

        {

            if (i == len - 1 && j == 0) continue;

            ans[i] = j;

            int tmp = M - (mod[i][num[i]] - mod[i][j]);

            tmp%=K;

            if (tmp < 0) tmp += K;

            if (dfs(left- 1,i - 1,tmp)) return true;

        }

         ans[i] = num[i];

    }

    //搜索比n大的从低位开始

    for (i = 0; i <= pos; ++i)

    {

        for (j = num[i] + 1; j < 10; ++j)

        {

            ans[i] = j;

            int tmp = M + mod[i][j] - mod[i][num[i]];

            tmp%=K;

            if (tmp < 0) tmp += K;

            if (dfs(left - 1,i - 1,tmp)) return true;

        }

        ans[i] = num[i];

    }

    rem[left][M] = pos + 1;

    return false;

}

int main()

{

    //freopen("d.txt","r",stdin);

    int i;

    while (~scanf("%s",s))

    {

        scanf("%d",&K);

        len = strlen(s);

        init();

        for (i = 0; i <= len; ++i)

        {

            if (dfs(i,len - 1,Mod)) break;

        }

    }

    return 0;

}

 

 

 

你可能感兴趣的:(git)