编程之美2.8——找符合条件的整数

任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0.

如N=3,M=39,N*M=111。

【思路】

这么难的思路打死我也想不到.@_@|||||..

将题目转换为,求一个数X,使得X%N=0且X的十进制表示只含有1和0.

维护一个“余数数组”,对于从0到N-1的每一个余数,都有相应的最小X;

高位可以利用低位的余数归队,X=10^k+Y(10的k次方,^表示次方)X%N=(10^k%N+Y%N).

直到找到余数为0对应的最小值。

【other code】——via xiaodongrush

int find_m(int n)
{
    if(n==1)
        return 1;
    int factor=10;
    int *A=new int[n];//A[i]保存余数为i时对应的最小数
    int *B=new int[n];//B[i]保存余数为i的当前数
    bool not_find=true;
    memset(A, -1, n*sizeof(int));
    A[1]=1;
    while(not_find){
        memset(B, -1, n*sizeof(int));
        int x=factor%n;//余数
        if(A[x]==-1){
            B[x]=factor;
            if(x==0)
                break;
        }
        for(int i=1; i<n; i++){
            if(A[i]==-1)
                continue;
            int new_x=(x+i)%n;
            if(A[new_x]==-1&&B[new_x]==-1){
                B[new_x]=factor+A[i];
                if(new_x==0){
                    not_find=false;
                    break;
                }
            }            
        }
        factor*=10;
        for(int i=0; i<n; i++){
            if(A[i]==-1&&B[i]!=-1)
                A[i]=B[i];
        }
    }
    int result=B[0];
    delete [] A;
    delete [] B;
    return result;
}

【评价】

维护两个数组,A保存余数对应的最小值,B保存当前值,每当有新余数时便扩展。按照书上的算法来的,十分严密,对于我来说已经很perfect了。

【书上的伪代码】

int find_m1(int n)
{
    int Noupdate=0;
    int i,j;
    vector<vector<int> > BigInt(n);
    for(int i=0; i<n; i++)
        BigInt[i].clear();
    BigInt[1].push_back(0);
    for(i=1, j=10%n; ; i++, j=(j*10)%n){
        bool flag=false;//判断是否更新
        if(BigInt[j].size()==0){
            flag=true;
            BigInt[j].clear();
            BigInt[j].push_back(i);
        }
        for(int k=1; k<n; k++){
            if((BigInt[k].size()>0)&& (i>BigInt[k][BigInt[k].size()-1])&& (BigInt[(j+k)%n].size()==0)){
                flag=true;
                BigInt[(j+k)%n]=BigInt[k];
                BigInt[(j+k)%n].push_back(i);
            }
        }
        if(flag==false) Noupdate++;
        else Noupdate=0;
        if(Noupdate==n||BigInt[0].size()>0)
            break;
    }
    if(BigInt[0].size()==0)
        return -1;
    else{
        int result=0;
        int factor=1;
        for(int k=0; k<BigInt[0].size(); k++){
            for(int r=0; r<BigInt[0][k]; r++)
                factor*=10;
            result+=factor;
            factor=1;
        }
        return result;
    }
}

【总结】

伪代码中10^k表示的是异或运算。用一个vector<vector<int> >来保存余数信息。

BigInt[i]是余数i对应最小数的有1的位置,比如对于n=3,BigInt[0] (0,1,2)代表第0,1,2位都有1,即111.

最后要转化成十进制表示。

原文地址:https://www.cnblogs.com/ketchups-notes/p/4514797.html