hdu1664 广搜

题意:同 poj 2283     给一个数字n,求n的倍数中,所使用不同数字最少的。例如1223含3个不同数字。如果有多个答案,取最小的。

分析:对于任意n,最多两个数字就能组成n的倍数。因为a,aa,aaa……取n+1个,则必有两个模n余数相同,相减即得n的倍数。

所以先考虑一个数字的情况,若没有n的倍数,再广搜两个数字。搜的时候要对余数判重,如果出现了相同的余数,则形成了循环。

另外搜两个数字的时候,要枚举这两个数字再搜,同时搜10个数字会爆空间。

 

 

const int M = 170000;
int ans[M], pa;
int a[M], p;//数字
int b[M],pre[M];//余数 前驱
int r[M];//余数判重

void check1(int *a, int p){//a[]当前答案 比ans[]小 则更新
    if(pa==-1 || pa>p){
        pa=0;
        FOR(i,0,p) ans[pa++]=a[i];
        return ;
    }
    if(pa<p)return;
    bool flag=false;
    FOR(i, 0, pa) if(ans[i]!=a[i]) {
        if(ans[i]>a[i]) flag=true;
        break;
    }
    if(flag) {
        pa=0;
        FOR(i,0,p) ans[pa++]=a[i];
    }
}

bool bfs1(int n){//一个数字
    pa = -1;
    FOE(i, 1, 9) {
        p=0;
        memset(r, 0, sizeof(int)*(n+3));
        int t = 0;
        FOR(j, 1, M){
            t = (t*10+i)%n;
            a[p++] = i;
            if(t==0) {check1(a,p);break;}
            else if(r[t]) break;
            else r[t]=1;
        }
    }
    if(pa!=-1){
        FOR(i, 0, pa)cout<<ans[i];cout<<endl;
        return true;
    }
    return false;
}

int aa[M], pp;
void check2(int p){
    pp=0;
    while(1){
        aa[pp++]=a[p];
        if(pre[p]==-1)break;
        p=pre[p];
    }
    FOE(i,0,(pp-1)/2) swap(aa[i],aa[pp-i-1]);
    check1(aa,pp);
}

queue<int> q;

void bfs2(int i,int j,int n){//两个数字
    memset(r, 0, sizeof(int)*(n+3));
    while(!q.empty())q.pop();
    p=0;
    
    if(i){ a[p]=i; b[p]=i%n; pre[p]=-1; r[b[p]]=1; q.push(p); p++; }
    a[p]=j; b[p]=j%n; pre[p]=-1; r[b[p]]=1; q.push(p); p++;

    while(!q.empty()){
        int t=q.front(); q.pop();

        a[p]=i; b[p]=(b[t]*10+i)%n; pre[p]=t;
        if(b[p]==0) check2(p);
        else if(r[b[p]]==0){r[b[p]]=1; q.push(p); p++;}

        a[p]=j; b[p]=(b[t]*10+j)%n; pre[p]=t;
        if(b[p]==0) check2(p);
        else if(r[b[p]]==0){r[b[p]]=1; q.push(p); p++;}
    }
}

int main(){
    #ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    int n;
    while(cin>>n, n){
        if( bfs1(n) ) continue;

        FOE(i, 1, 9) FOE(j, 0, 9) if(i>j)
            bfs2( j, i, n );

        FOR(i, 0, pa) cout<<ans[i]; cout<<endl;
    }

    return 0;
}

 

posted @ 2013-05-09 22:17  心向往之  阅读(224)  评论(0)    收藏  举报