(HDU 1664)Different Digits BFS + 数论 + 余数判重 详细题解

来源:互联网 发布:二手货车估价软件 编辑:程序博客网 时间:2024/05/20 05:31

Different Digits
Time Limit: 10000/4000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1628 Accepted Submission(s): 470

Problem Description
Given a positive integer n, your task is to find a positive integer m, which is a multiple of n, and that m contains the least number of different digits when represented in decimal. For example, number 1334 contains three different digits 1, 3 and 4.

Input
The input consists of no more than 50 test cases. Each test case has only one line, which contains a positive integer n ( 1<=n < 65536). There are no blank lines between cases. A line with a single `0’ terminates the input.

Output
For each test case, you should output one line, which contains m. If there are several possible results, you should output the smallest one. Do not output blank lines between cases.

Sample Input
7
15
16
101
0

Sample Output
7
555
16
1111

Source
2004 Asia Regional Shanghai

题意:
给你一个正整数n,问你在n的倍数中使用数的种类最少的是哪一个?若有多个使用数的种类一样最少,那么输出值最小的那个

分析:
通过写了(HDU 1226)超级密码 感觉这题也错不多,但是就是想不出来。。。

要写这题一定要知道这样一个数论结论,不然就GG了。。。

对于任意的整数n,必然存在一个由不多于两个的数来组成的一个倍数。
因为a,aa,aaa……取n+1个,则必有两个模n余数相同,相减即得n的倍数m。而m只由a、0组成。

所以我们只需要考虑两种情况:
1:所求的数只由一个数字构成
2:所求的数由两个数字构成
这两种情况我们都可以经过枚举来确定所要求的数能够由哪些数字构成

当我们确定了所要求的数能够由哪些数字构成时,那就和(HDU 1226)超级密码http://blog.csdn.net/stillxjy/article/details/71699544 这一题是一样的了:
摘自(HDU 1226)超级密码http://blog.csdn.net/stillxjy/article/details/71699544

对于两个数 s1,s2 (s1 < s2) ,若s1 % n == s2 % n
那么当我们在s1,s2后面同时添加一位a时,那么改变之后的 s1’ ,s2’ 任然满足 s1’ % n == s2’ % n;
即无论是大数还是小数如果模n同余那么再添上其他数字的话再模n还是同余的
所以一切由s2可以取到的余数的结果,都可以以相同的方式用s1取得,并且用s1时结果小。
所以对于每一个余数r,当我们在从小到大构造s,只用选取第一个出现的s % n == r 的s,即每一个r在队列中只会出现一次

具体实现过程:
由于不知道最后这个数有多少位,并且要是像HDU 1226那样用一个数组来保存当前所构造的结果很浪费
所以我们可以按下面的方法来实现:

struct node{    int d,val,pre,cnt;   //构造的数的 d:最后一位的值 val:当前的余数值 pre:前一位的位置 cnt:当前的长度}cur, now,q[maxn];

结构体中保存以上信息,我们使用数组自己来模拟队列,所以只需要在结构体中保存当前的最后一位的数值和前一位的位置,那么最后我们通过递归即可快速找出所构造的数
具体详细过程请看代码中的注释

#include <iostream>#include <cstdio>#include <string>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int maxn = 65550;struct node{    int d,val,pre,cnt;   //构造的数的 d:最后一位的值 val:当前的余数值 pre:前一位的位置 cnt:当前的长度}cur, now,q[maxn];int n,mcnt,tcnt,en;int a[5];                //a[]用来保存所构造的数可以使用的数值,最多两个不同的数值bool vis[maxn];          //余数判重string ans,tans;         //最后结果,当前结果void getans(int k)       //递归求出所构造的数{    char c;    if(k == -1) return ;    getans(q[k].pre);    c = q[k].d + '0';    tans += c;}bool bfs(int k){    int nval,ncnt,tval;    int head = 0,tail = -1;    memset(vis,0,sizeof(vis));    for(int i=1;i<=k;i++) //第一位的数有k种情况    {        if(a[i]) //第一位不能为0        {            now.cnt = 1;            now.d = a[i];            now.val = a[i] % n;            now.pre = -1;            vis[now.val] = 1;            q[++tail] = now;        }    }    while(head <= tail)    {        now = q[head];        nval = now.val;        ncnt = now.cnt;        if(ncnt > mcnt) break;        if(nval == 0) //找到n的倍数        {            en = head;            tcnt = ncnt;            return true;        }        for(int i=1;i<=k;i++) //每一位有k种可能的数        {            tval = (nval * 10 + a[i]) % n;            if(!vis[tval])            {                vis[tval] = 1;                cur.cnt = ncnt + 1;                cur.d = a[i];                cur.pre = head;                cur.val = tval;                q[++tail] = cur;            }        }        head++;    }    return false;}int main(){    while(scanf("%d",&n)!=EOF && n)    {        int flag = 0;        ans = "NOT";        mcnt = 1000000000;        for(int i=1;i<=9;i++) //只由一个数字构成        {            a[1] = i;            if(bfs(1))            {                tans = "";                getans(en);                if(mcnt > tcnt || mcnt == tcnt && ans > tans)                {                    mcnt = tcnt;                    ans = tans;                }            }        }        if(ans != "NOT")        {            cout<<ans<<endl;            continue;        }        for(int i=0;i<=9;i++) //由两个数构成        {            a[1] = i;            for(int j=i+1;j<=9;j++)            {                a[2] = j;                if(bfs(2))                {                    tans = "";                    getans(en);                    if(mcnt > tcnt || mcnt == tcnt && ans > tans)                    {                        mcnt = tcnt;                        ans = tans;                    }                }            }        }        cout<<ans<<endl;    }    return 0;}
1 0
原创粉丝点击