题目: 给一个数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 <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 6000;
const int M = 100001;
int n, m, end, cnt, num[M], wnum[M];
bool vis[N];
struct NODE {
int idn, x, p, id;
}e[N];
int solve ( int x ) {
if ( x == 0 ) return 1;
int ans = 0;
while ( x > 0 ) {
ans += 1;
x /= 10;
}
return ans;
}
int fun( int x ) {
int ans = 1;
for ( int i = 0; i < x; ++i ) ans *= 10;
return ans;
}
bool cmp ( int a, int b ) { return a < b; }
bool bfs() {
queue <NODE> Q;
for ( int i = 0, x; i < m; ++i ) {
x = num[i] % n;
if ( !vis[x] && num[i] ) {
vis[x] = true;
e[cnt].x = x, e[cnt].idn = num[i], e[cnt].p = -1, e[cnt].id = cnt;
Q.push(e[cnt]);
if ( x == 0 ) {
end = cnt;
return true;
}
cnt++;
}
}
while ( !Q.empty() ) {
NODE u = Q.front(); Q.pop();
for ( int i = 0; i < m; ++i ) {
int x = (u.x * fun( wnum[i] ) + num[i]) % n;
//printf("%d\n", x);
if ( !vis[x] ) {
vis[x] = true;
e[cnt].x = x, e[cnt].p = u.id, e[cnt].idn = num[i], e[cnt].id = cnt;
if ( x == 0 ) {
end = cnt;
return true;
}
Q.push( e[cnt] );
cnt++;
}
}
}
return false;
}
void outprintf( int x ) {
if ( x == -1 ) return;
outprintf(e[x].p);
printf("%d", e[x].idn);
}
int main()
{
while ( scanf("%d%d", &n, &m) == 2 ) {
cnt = 0;
for ( int i = 0; i < m; ++i ) scanf("%d", &num[i]);
if ( n == 0 ) {
printf("0\n");
continue;
}
sort( num, num + m, cmp );
for ( int i = 0; i < m; ++i ) wnum[i] = solve( num[i] );
memset(vis, 0, sizeof(vis));
if ( bfs() ) outprintf( end );
else printf("0");
printf("\n");
}
}