題意是: 給出一個 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;
}