HDU 1664 Different Digits (数论 -- 鸽笼原理 + BFS搜索 + 余数判重)

来源:互联网 发布:vb.net和c#区别 编辑:程序博客网 时间:2024/06/05 03:52

大体题意:

给你一个数字n,让你找出它的一个倍数m,使得m中不同的数字尽可能的少,如果有多解,输出最小的一个!

思路:

肯定是搜索的题目,我们得先考虑数字m 不同数字的种类个数,以便缩小搜索范围。

这里巧妙的运用了鸽笼原理,举个简单的小例子来说明这个原理,如果让你选择一个月份的话,你选择13次肯定有两次是重复的,这个题目同样也是,我们选择n+1个数字,肯定有两个数对n取模是相同的。我们这样的数取由1种数字组成!

那么num1 = AAAAAAAAA

       num2 = AAAA

那么num1 - num2肯定是n的倍数   num1 - num2  = AAAA00000的形式!

所以说最多两种数字就一定有解!!!

那么肯定先搜索由1种数字组成的,在搜索两种数字组成的!

有两个剪枝:

1.搜到目前为止,字符串长度已经长于已经更新好的答案了 直接return了!

2.搜到当前数字对n 取模与之前重复的话,就不搜了。

这个很好理解:

先想搜索1种数字的,当你取模完后 值于之前重了,那么你下一步取模 肯定也会重复,因此形成循环!

在想想搜索2种数字的,如果下一步取模方式与之前一样的话,肯定是循环的,不用搜!

如果方式不同那么就可以由前面的那个位置继续搜!

因此 只要余数重复就停止搜索!


这里也有一些技巧:

因为搜索两种数字 时  得记录字符串前指针,因此这里bfs 手写队列会比queue好很多,还省了不少空间!

#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <string>using namespace std;const int inf = 0x3f3f3f3f;struct Node{    char ch;    int mod;    int la;    int len;}qq[1000000];int head,tail;int anslen = inf;int num[10],n;bool vis[65540];string res;bool bfs1(int k){    memset(vis,0,sizeof vis);    int v = 0;    string ans = "";    int len2 = 0;    while(1){        ans += '0' + k;        ++len2;        if (len2 > anslen)return false;        v = (v * 10 + k) % n;        if (!v){            if (anslen == inf || ans.length() < anslen || (ans.length() == anslen && ans < res)){                res = ans;                anslen = ans.length();                return 1;            }            return 0;        }        if (vis[v])return 0;        vis[v] = 1;    }}void dfs(string& ans,int cur){    if (~cur)dfs(ans,qq[cur].la);    else {        return ;    }    ans += qq[cur].ch;}bool bfs2(int num1,int num2){    memset(vis,0,sizeof vis);    head = tail = 0;    int flag = 0;    if (num1){        qq[tail].ch = num1 + 48;        qq[tail].mod = num1 % n ;        qq[tail].len = 1;//        vis[qq[tail].mod ] = 1;        qq[tail++].la = -1;    }    qq[tail].ch = num2 + 48;    qq[tail].mod = num2 % n ;    qq[tail].len = 1;//    vis[qq[tail].mod ] = 1;    qq[tail++].la = -1;    num[0] = num1, num[1] = num2;    while(head < tail){        if (qq[head].len > anslen)return false;        if (vis[qq[head].mod ]){            ++head;            continue;        }        vis[qq[head].mod ] = 1;        if (qq[head].mod == 0){            string ans = "";            dfs(ans,head);////            if (ans == "16")puts("haha");            if (anslen == inf || ans.length() < res.length() || (ans.length() == res.length() && ans < res)){                res = ans;                anslen = ans.length();                return 1;            }            return 0;        }        for (int i = 0; i < 2; ++i){            int mod = (qq[head].mod * 10 + num[i]) % n;//            if (vis[mod])break;//            vis[mod] = 1;            qq[tail].ch = num[i] + 48;            qq[tail].mod = mod;            qq[tail].len = qq[head].len+1;            qq[tail++].la = head;        }        ++head;    }    return 0;}int main(){    while(~scanf("%d",&n) && n){        bool ok = 0; res = ""; anslen = inf;        for (int i = 1; i < 10; ++i){            if (bfs1(i)){                ok = 1;            }        }        if (ok){            printf("%s\n",res.c_str());            continue;        }        for (int i = 0; i < 10; ++i){            for (int j = i + 1; j < 10; ++j){                if (bfs2(i,j)){                    ok = 1;                }            }        }        printf("%s\n",res.c_str());    }    return 0;}

Different Digits

Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1580    Accepted Submission(s): 445


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
7555161111
 

Source
2004 Asia Regional Shanghai
 

Recommend
xhd
 



0 0