链接:http://poj.org/problem?id=1465
题意:给一个数字n,和m个数字,找一个由这些数字组成的最小的n的倍数,如果不存在输出0。
思路:这题怎么想都想不到bfs上去,看了别人的解题报告,其实是用bfs来枚举,但是加了一个牛逼的剪枝:同余。即如果A%X==B%X,则(A*10+K)%X==(B*10+K)%X。
我们枚举m中每一个数字做这个K,实际上是枚举了一个数,B*10是之前枚举的数字,如果这个数%X得到的值之前已经得到过,则没必要再往下计算,因为根据同余定理剩下的枚举值和之前的枚举值得到的余数肯定相同,所以没必要再计算。这个剪枝保证了即使一直没找到最小倍数也不至于把数字算到无穷大去,因为n的范围为[0,4999],所以最多只会处理它5000次余数,当余数为0就找到了答案。
为了使得到的答案最小,先对m个数字排序。
细节:n==0时需要特判,X%0会RE出翔。不能用stl的queue,会TLE。
#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 500100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct node{
int mod,num,father;
int id;
}a[20000];
int n,m,cnt,tot;
int flag[5010],b[5010],ans[50010],ff;
void bfs(){
int i,j;
int front = 0, rear = 1;
node t1,t2;
a[front].mod = 0;
a[front].num = 0;
a[front].father = -1;
while(front<rear){
t1 = a[front];
for(i=0;i<m;i++){
if(!flag[(t1.mod*10+b[i])%n]&&(t1.father!=-1||b[i]!=0)){
flag[(t1.mod*10+b[i])%n] = 1;
a[rear].mod = (t1.mod*10+b[i])%n;
a[rear].num = b[i];
a[rear].father = front;
if(a[rear].mod==0){
node temp = a[rear];
ans[tot++] = b[i];
while(1){
temp = a[temp.father];
if(temp.father==-1) break;
ans[tot++] = temp.num;
}
return ;
}
rear++;
}
}
front++;
}
ff = 1;
}
int main(){
int i,j;
while(scanf("%d",&n)!=EOF){
ff = tot = cnt = 0;
memset(flag,0,sizeof(flag));
scanf("%d",&m);
for(i=0;i<m;i++){
scanf("%d",&b[i]);
}
sort(b,b+m);
if(n==0){
puts("0");
continue;
}
bfs();
if(ff){
puts("0");
continue;
}
for(i=tot-1;i>=0;i--){
printf("%d",ans[i]);
}
puts("");
}
return 0;
}