ZOJ 1136 Multiply

题目: 给一个数N,N>= 0, N < 5000, 然后给出m个数,求N的最小倍数,这个倍数比一定是有这m个数组成,比如N=12, m个数里面有1,2, 那么12是N的最小倍数,是有m个数字中的1和2合成的。注意,m中的每个数字是可以重复使用的。

解析:

第一,分析可知,由于它是加的位数,而不是数字,所以,对于数一定要有处理,不可能盲目的追加位数!

第二,这m个数,根据题意,可以组成的数字是无穷多的

所以,这里需要一个解决的办法,那就是取余。事实上,任何一个数对n取余,一共只能有n个结果(如果算0的话)。而且有这样的一个式子,如果x%n == y%n, 那么x%n * 10 + c == y%n *10 + c,由此可见,我们只要判断这个余数即可,将所得的余数和剩下的m个数组和,如果得到的数对n取余的余数之前组和过,那么就不需要再进行判断了,因为,之前已经判断过了。也就是说,这里和m个数是谁不重要,重要的是,这个余数,一旦这m个数组和成的数。

接下来说一下大致的算法:

首先将m个数从下到大排序,这样在bfs的过程中也是从小到大遍历,保证结果最小。

然后,开始bfs,建立一个vis数组,来记录n的那些已经遍历过的余数,队列里面存储的也是余数,然后从小到大遍历。比较重要的是记得建立一个父节点数组,用来输出。

最后要注意的是,对于父节点数组,要指向的节点是自己新建立的,而不是那m个数,这个很容易想到。

解释一下代码:结构体NODE里面,存储这个点的id,余数,父节点,和对应的数。bfs判断是否存在一个这个倍数,outprintf递归输出。bfs中,第一个for循环, 算是用来初始化的,有一点要注意的是,0不能加入到队列里面,因为求的是最小正整数。然后后面的那个while就正常做了。


#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <set>
#include <list>
#include <queue>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define maxn 70
#define mem(a) memset(a,0,sizeof(a))
const double eps = 1e-10;
struct node
{
    string num;
    int mod;
    node(){}
    node(string a,int b)
    {
        num = a;
        mod = b;
    }
}tmp;
int n,m,a[11],vis[50005];
string ans;
int solve()
{
    queue<node> q;
    q.push(node("",0));
    mem(vis);
    while(!q.empty())
    {
        node p = q.front();
        q.pop();
        for(int i = 0; i < m; i++)
        {
            tmp.num = p.num + char('0'+a[i]);
            tmp.mod = (p.mod*10 + a[i]) % n;
            if(tmp.num != "0" && tmp.mod == 0)
            {
                ans = tmp.num;
                return true;
            }
            else if(vis[tmp.mod] == 0 && tmp.num != "0")
            {
                q.push(tmp);
                vis[tmp.mod] = 1;
            }
        }
    }
    return 0;
}
int main()
{
    int t,c = 0;
    //scanf("%d",&t);
    while(scanf("%d%d",&n,&m) != EOF)
    {
        int flag = 0;
        for(int i = 0; i < m; i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a,a+m);
        if(!n)
            printf("0\n");
        else if(solve())
            cout << ans<<endl;
        else
            printf("0\n");
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值