题意是: 给出一个 0 - 4999 的数 N ,在给出 M 个0-9的数,判断这M个数字能不能构成一个数是N的倍数,如果有输出最小的,如果没有输出0。
此题用BFS 。。 这个题好在 用 余数判重剪枝。。
BFS 如果不加以剪枝,一定会搜索的情况会很庞大。所以应该用余数判重 。
为什么可以用余数判重?
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<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<vector>
#define LL long long
#define inf 0x7fffffff
#define eps 1e-7
#define N 5509
#define M 20009
using namespace std;
int T,n,m,k;
struct Node
{
LL v;
int w;
int pre;
} a[N];
int h[100];
int vis[N];
void print(int x)
{
if(x)
{
print(a[x].pre);
printf("%d",a[x].w);
}
}
void bfs()
{
int l=0,r=1;
a[0].pre=a[0].w=a[0].v=0;
while(l<r)
{
Node t;
t=a[l];
t.pre=l++;
int v=t.v;
for (int i=0; i<m; ++i )
{
int x=(v*10+h[i])%n;//n不能是0,Float-Point Error
if(x==0&&l!=1)
{
print(t.pre);
printf("%d\n",h[i]);
return ;
}
if(vis[x]||(l==1&&h[i]==0))continue;
vis[x]=1;
t.v=x;
t.w=h[i];
a[r++]=t;
}
}
printf("0\n");
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ex.in","r",stdin);
#endif
int ncase=0;
while (scanf("%d%d",&n,&m)==2)
{
memset(vis,0,sizeof(vis));
for(int i=0; i<m; ++i)
{
scanf("%d",&h[i]);
}
if (n==0)//
{
printf("0\n");
continue;
}
sort(h,h+m);
bfs();
}
return 0;
}