hdu Different Digits 1664

/*

和poj2283是同一道題

題意:給你一個數n找到一個數先要保證這個數的元素最少,在保證元素最少的情況下,保證這個數最小,元素最少指的是,
111111就是一個元素,12222就是連個元素。
思路:
對於任意的整數 n ,必然存在一個由不多於兩個的數來組成的一個倍數。 因爲 a , aa , aaa…… 取 n+1 個,
則由鴿籠原理(抽屜原理),必有兩個模 n 餘數相同,相減即得 n 的倍數 m 。而 m 只由 a 、 0 組成。
對於餘數相同的情況,數位少的含不同數字的個數肯定不超過數位多的,所以可以用餘數判重。
*/
#include<stdio.h>
int pr[2][65540],q[65536*2],p[65536*2],n;//pr數組是輸出數組,q[]是隊列數組,p是隊列的前指針數組
int bfs(int a,int b,int t)
{
    int fr=0,r=1,f[65540]= {0},i;//fr存的是隊列的前指針,r存的時候指針,f是餘數標記數組
    q[0]=0;//q這個隊列的元素是一個個餘數
    p[0]=0;
    if(a==0)//當a爲零時,a不能在數的開頭,爲了下面還原數的的時候,保持奇偶性不變
    {
        q[2]=b;
        p[2]=0;
        fr=2;
        r=3;
    }
    while(fr<r)
    {
        if(f[q[fr]]==1)//因爲入隊時我們沒有判斷餘數是否出現過,所以開頭的時候,先判斷餘數是否出現過
        {
            fr++;
            continue;
        }
        f[q[fr]]=1;//沒出現過的餘數把它標記爲已經搜過
        q[r]=(q[fr]*10+a)%n;//用餘數去搜a
        p[r]=fr;//記錄fr的值,表明q[r]這個餘數是由q[fr]搜過來的
        if(q[r]==0)//餘數爲0跳出循環
            break;
        r++;//隊列的後指針向後移一位,因爲a已經搜過
        q[r]=(q[fr]*10+b)%n;
        p[r]=fr++;//fr向後移一位,因爲q[fr]已經搜過a,b了需要向下搜索
        if(q[r]==0)
            break;
        r++;
    }
    if(fr<r)
    {
        for(i=0; r!=0; i++)
        {
            if(r%2==0)//當r爲偶數時搜的一定是b
                pr[t][i]=b;
            else
                pr[t][i]=a;
            r=p[r];//把r退回到上一層指針
        }//這樣我們就把數還原了出來,但是是倒序存的
        return i-1;
    }
    return -1;
}
int main()
{
    int i,j,m,t,c;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        int d[10];
        c=0;
        d[0]=n;
        for(i=1; i<=9; i++)//判斷一個元素是否是n的倍數
        {
            d[i]=1;
            j=i;
            while(d[i]<n&&j%n!=0)//j%n是一個技巧
            {
                j=(j*10+i)%n;
                d[i]++;
            }
            if(d[i]<d[c])//當d[i]<d[c]的時候說明找到了一個更小的
                c=i;
        }
        if(c!=0)//當c非等於0時就說明一個元素的存在,且爲d[c]個c
        {
            for(i=0; i<d[c]; i++)
                printf("%d",c);
        }
        else
        {
            t=0;//t這個變量也是一個技巧,當我們判斷一個數是否大於上一個數的時候,不需要再把這個數複製一遍,直接在廣搜把這個數覆蓋就可以了
            m=n;//m一隻記錄的是當前數的位數,如果找到小於m的就更新m的值
            for(i=0; i<10; i++)
                for(j=i+1; j<10; j++)
                {
                    c=bfs(i,j,t);
                    if(c!=-1&&c<m)//如果c小於m的話就更新m的值
                    {
                        m=c;
                        t=t^1;//廣搜還原數的時候還原到相對的位置如果t是0就還原到pr[1][]數組裏否則就是pr[0][]數組裏
                    }
                    else if(c==m)//當c==m的話就要比較兩個數的大小
                    {
                        for(int k=m; k>=0; k--)//因爲我們還原出來的數是倒序,所以比較的時候也應該從後往前
                        {
                            if(pr[t][k]>pr[1-t][k])
                            {
                                break;
                            }
                            else if(pr[t][k]<pr[1-t][k])
                            {
                                t=t^1;
                                break;
                            }
                        }
                    }
                }//最後t只記錄的較大的那個數行所以1-t或者1^t
            for(i=m; i>=0; i--)//倒序輸出這個數
                printf("%d",pr[1^t][i]);
        }
        printf("\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章