hdu Different Digits 1664

来源:互联网 发布:淘宝图片修图私活 编辑:程序博客网 时间:2024/06/04 17:56

/*

和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;
}
0 0