题意:现在给你M个数字和另外一个数N(N<5000),问你能否用这M个数字中的一个或几个(可以重复)来构成一个数,使得这个数能被N整除,如果能输出最小的,不能输出0
显然可以将构成的数字位数作为层数来进行bfs,通过对给你的M个数进行排序,来保证最先出现的肯定是最小的。
关键问题是如何判重?
因为有两个数要是被N除之后余数相等,那么在这两个数后面添加相同个数字之后余数也必定相等
A = a*N+C
B = b*N+C
(A*10+k)%N = C*10+k%N=(B*10+k)%N
所以每个数作为前缀的时候一样的余数的只需要出现一次即可,就可以判重了。
#include <cstdio> #include <iostream> #include <cstdlib> #include <set> #include <map> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <cstring> #include <string> using namespace std; int N,M,num[1000]; int val[5555],pre[5555]; int len[5555],res[5555]; bool tab[5555]; bool notzero(int id) { return !(len[id] == 1 && val[id] == 0); } void print_path(int now) { if(~pre[now]) print_path(pre[now]); putchar(val[now] + '0'); } int main() { while(scanf("%d%d",&N,&M) != EOF) { memset(tab,0,sizeof(tab)); for(int i = 0;i < M;i++) { scanf("%d",&num[i]); } sort(num,num + M); if(N == 0) { puts("0"); continue; } int front = 0,rear = 0; for(int i = 0;i < M;i++) { len[rear] = 1; res[rear] = num[i] % N; pre[rear] = -1; val[rear] = num[i]; rear++; if(num[i] != 0) { tab[num[i] % N] = true; } } int ans = 0; while(front < rear) { int now = front; front++; if(res[now] == 0 && notzero(now)) { ans = now; break; } for(int i = 0;i < M;i++) { if(!notzero(now) && num[i] == 0) continue; int nres = (res[now] * 10 % N + num[i] % N) % N; if(tab[nres] == false) { tab[nres] = true; len[rear] = len[now] + 1; res[rear] = nres; pre[rear] = now; val[rear] = num[i]; rear++; } } } if(ans == 0) puts("0"); else { print_path(ans); putchar(' '); } } return 0; }