BFS+同余
以余数作为状态做BFS,目标状态为余数为0假设存在两个数A,B对N取余相同,且A<B,那么A和B同时加或者乘同一个数得到的两个数对N取余仍然是相同的,由此能得出的结论是,假设A和B作为状态做BFS,B能得到的余数,A也一定能得到,我们要求的目标状态是余数为0,那么如果队列里面已经有了一个余N为x的数,如果当前的数余N也为x,那么当前这个数就可以不要,这样能避免重复遍历状态。
题目要求的倍数的位数可能很大,所以需要给每一个节点设置一个指向前驱的变量,每一个节点只要记录当前位的位数,通过前驱能得到BFS的路径,由此就能得到整个倍数的值。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#include <map>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int Maxn = 10000+10;
const int INF = 0x3f3f3f3f;
struct Node {
int pre, r, dig;
} qu[Maxn];
int d[Maxn], n, m, head, tail, a[Maxn];
char S[Maxn];
bool vis[5500];
int main(void)
{
while(scanf("%d", &n) != EOF) {
scanf("%d", &m);
for(int i = 0; i < m; ++i) scanf("%d", &d[i]);
sort(d, d+m);
if(n == 0) printf("0\n");
else {
head = tail = 0;
Node tmp;
memset(vis, false, sizeof(vis));
for(int i = 0; i < m; ++i) {
if(d[i] == 0) continue;
tmp.r = d[i]%n;
tmp.pre = -1;
tmp.dig = d[i];
vis[tmp.r] = true;
qu[tail++] = tmp;
}
bool ok = false;
while(head < tail) {
tmp = qu[head++];
if(tmp.r == 0) {
ok = true;
head--;
break;
}
for(int i = 0; i < m; ++i) {
Node cur = tmp;
cur.r = (cur.r*10+d[i]) % n;
if(!vis[cur.r]) {
vis[cur.r] = true;
cur.pre = head-1;
cur.dig = d[i];
qu[tail++] = cur;
}
}
}
if(!ok) printf("0\n");
else {
int cnt = 0;
for(int i = head; i != -1; i = qu[i].pre) a[cnt++] = qu[i].dig;
int ct = 0;
for(int i = cnt-1; i >= 0; --i) S[ct++] = a[i]+'0';
S[ct] = '\0';
puts(S);
}
}
}
return 0;
}
浙公网安备 33010602011771号