hdu搜索

hdu 4294

题意: 给出一个n(n<=10000)和k(2<=k <=10),现在想求出一个数M,M是n的倍数,现在让M用k进制表示。

 要求: 表示成k进制后所含的不同数字的数目最小。如果有多组解输出值最小的一组。

思路: 首先有一个定理,就是在k进制下最多需要两个不同的数字就可以表示出n的整数倍。

下面简单证明一下。aaa......aaaaa mod n可以得到的数最多有n个,当这个串很长之后肯定有两个数mod n后是想等的,将这两个数相减就是n的倍数,但是这里雀只有两个数字。 由此得证,最多只需要两个数字就行。

接下来首先看一个数字行不行。如果一个数字就行的话那么就直接得出结果。 否则的话就枚举两个数字,我先枚举的是首位的数字,然后再枚举另外一个数字。这里用bfs, 表示对bfs理解的还不够啊。 类似于最短路,开始的时候wa了好几次,后来知道是bfs往后添加数的顺序出现了问题,应该现往后添加小的,再往后添加大的,这样才能保证解的最优性。

AC代码:

View Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 11100, INF = 1<<29;

struct
{
    int u,num;
} p1, p2;

int n, k, f[N], ans[N], pre[N], now[N];
queue<int>q;

void solve()
{
    int ans1 = INF, tp, t;
    p1.num = INF;
    for(int i=1; i<k; i++)
    {
        tp = 0;
        for(int j=1; j<=n+1; j++)
        {
            tp *= k;
            tp += i;
            tp %= n;
            if(tp == 0)
            {
                if(p1.num > j)
                {
                    p1.u = i;
                    p1.num = j;
                    break;
                }
            }
        }
    }
    if(p1.num != INF)
    {
        for(int i=1; i<=p1.num; i++)
            printf("%d",p1.u);
        printf("\n");
        return ;
    }

    for(int i=1; i<k; i++)
    {
        for(int j=0; j<k; j++)
        {
            while(!q.empty())
                q.pop();

            memset(f, 0, sizeof(f));
            pre[i%n] = 0;
            f[i%n] = 1;
            int u, v;
            q.push(i%n);

            while(!q.empty())
            {
                u = q.front();
                q.pop();
                if(u == 0) break;
                if(i < j) t = i;
                else t = j;
                 v = (u*k + t)%n;
                if(!f[v])
                {
                    f[v] = f[u]+1;
                    pre[v] = u;
                    if(v == 0) break;
                    q.push(v);
                }

                if(i < j) t = j;
                else t = i;
                v = (u*k + t)%n;
                if(!f[v])
                {
                    f[v] = f[u]+1;
                    pre[v] = u;
                    if(v == 0) break;
                    q.push(v);
                }
            }

            u = 0;
            for(int w=f[0]; w>0; --w)
            {
                v = pre[u];
                now[w] = ((u-v*k)%n+n)%n%k;
                u = v;
            }
            if(f[0] < ans1 && f[0] != 0)
            {
                ans1 = f[0];
                memcpy(ans,now,sizeof(ans));
            }
            else if(f[0] == ans1 && f[0] != 0)
            {
                for(int w=1; w<=ans1; w++)
                {
                    if(ans[w] != now[w])
                    {
                        if(now[w] < ans[w])
                        {
                            memcpy(ans,now,sizeof(ans));
                        }
                        break;
                    }
                }
            }
        }
    }
    for(int i=1; i<=ans1; i++)
    {
            printf("%d",ans[i]);
    }
    printf("\n");
}

int main()
{
    while(scanf("%d%d", &n, &k) != EOF)
    {
        solve();
    }
}

 

 

 

 

posted @ 2012-09-18 20:41  Gu Feiyang  阅读(238)  评论(0)    收藏  举报