ZOJ 1136 Multiple

Multiple

Time Limit: 10 Seconds      Memory Limit: 32768 KB

a program that, given a natural number N between 0 and 4999 (inclusively), and M distinct decimal digits X1,X2..XM (at least one), finds the smallest strictly positive multiple of N that has no other digits besides X1,X2..XM (if such a multiple exists).

The input file has several data sets separated by an empty line, each data set having the following format:

On the first line - the number N
On the second line - the number M
On the following M lines - the digits X1,X2..XM.

For each data set, the program should write to standard output on a single line the multiple, if such a multiple exists, and 0 otherwise.

An example of input and output:


Input

22
3
7
0
1

2
1
1


Output

110


    这道题是一道BFS的题目,因为要输出最小的那个倍数,所以一开始我们要对那M个数进行由小到大排序,这样最后求出的答案才是最小值,这道题还要注意一个剪枝,就是利用余数去重,因为我们广搜的时候是由小到大搜索的,所以我们可以记录每一个数取余N的余数,这样如果后面遇到一个数取余N的结果正好在前面出现了,那就不需要去管他了。因为如果:

    A=a*N +e  即A%N =e

    B=b*N+e   即B%N=e

 当A B mod N的余数相同时,如果先出现A 。

 在A后加上一个数 i 时,新的数C = 10 *a*N + 10 *e+i;同样B后加上数 i 时,D = 10*b*N +10*e+i;由于C D 前边 10*a*N 和 10*b*N 都是N的倍数则C D mod N 的余数都是有10*e+i 决定的。

 于是 C D  mod N 同余。

 因此 A B 同余,都添加上 i 之后,新的两个数C D也是同余的。在无论添加多少个数,新生成的两个数也是同余的。

 因此 在A 之后如果不出现 N的倍数 ,则在B之后也不会出现。 在A 之后出现,那B之后也会出现。又因为要求 求最小值。所以只需要搜索min(A,B)之后的 ,对于另外一个数之后就不用搜索了。

    所以贴出代码(相关解释有注释说明):

#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
using namespace std;

struct Que
{
    Que(){ s=""; mod=0;}
    string s;//用来记录倍数
    int mod;//用来记录余数
};
int digit[15];
bool vis[5000+10];//用来余数判重
int N,M;
string ans;//记录最终结果

bool BFS()
{
    memset(vis,0,sizeof(vis));

    queue<Que> que;
    Que t;
    que.push(t);

    while(!que.empty())
    {
        Que p=que.front();
        que.pop();

        for(int i=0;i<M;i++)
        {
//            cout<<" dsaf"<<endl;
            Que temp;
            temp.s=p.s+(char)(digit[i]+'0');
            temp.mod=(p.mod*10+digit[i])%N;

            if(temp.mod==0&&temp.s!="0")
            {
                ans=temp.s;
                return true;
            }else if(!vis[temp.mod]&&temp.s!="0")//如果之前没有这个余数,就入队
            {
                que.push(temp);
                vis[temp.mod]=1;
            }

        }
    }

    return false;
}

int main()
{
//    freopen("s","r",stdin);

    while(scanf("%d%d",&N,&M)!=EOF)
    {
        for(int i=0;i<M;i++)
            scanf("%d",&digit[i]);

        sort(digit,digit+M);//由小到大排序

        if(N==0)    {  cout<<0<<endl;}
        else if(BFS())  { cout<<ans<<endl;}
        else  {  cout<<0<<endl;}
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值