http://acm.hdu.edu.cn/showproblem.php?pid=4474
题意:给出一个数,和一些数字,求这个数最小的倍数,使得给出的数字不能出现。
如果暴力枚举这个数的倍数的话,首先不知道什么时候是无解的情况,其次是如果答案很大会爆LL,而且速度也很慢。所以想到用BFS,从个位开始开始枚举数字0~9中可以出现的数字,然后个位变成十位,再枚举个位,第一个满足是给出的数的倍数的数就是答案。还可以剪枝,在搜到一半的情况下,A,B都不是答案,但是A%n = B % n 并且A<B 那么B不用继续搜下去了,答案只可能是往A后面再添数。这个剪枝加上了,就保证BFS会停下来,标记数组a起到了作用。如果当前的数是x,后面加了一位y,那么(x*10+y)%n=(x%n*10+y)%n 只要模一样,都是n,那么可以在任意的位置取模结果还是一样的。正因为这个等式成立所以只需要把每一个数%n的结果保存下来就可以。还有些细节要注意,一开始把可能的个位数先进队列,操作和后面一样,但是0不能进队列,0 mod n= 0,但是0又不是n的倍数(n!=0)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<string>
#include<iostream>
using namespace std;
struct Node
{
string ch;
int ys;
};
struct Node p, v;
queue <Node> q;
int flag[20], a[10005];
int main()
{
int n, m, Flag, tmp;
char c;
string ans;
int tt = 1;
while (~scanf("%d", &n) && n != 0)
{
scanf("%d", &m);
Flag = 0;
memset(flag, 0, sizeof(flag));
memset(a, 0, sizeof(a));
for (int i = 1; i <= m; i++)
{
scanf("%d", &tmp);
flag[tmp] = 1;
}
while (!q.empty()) q.pop();
for (int i = 1; i <= 9; i++)
if (flag[i] == 0 && a[i % n] == 0)
{
c = '0' + i;
p.ch = c;
p.ys = i % n;
a[p.ys] = 1;
q.push(p);
if (p.ys == 0)
{
ans = p.ch;
Flag = 1;
break;
}
}
if (Flag == 0)
{
while (!q.empty())
{
v = q.front();
q.pop();
for (int i = 0; i <= 9; i++)
if (flag[i] == 0 && a[(v.ys*10+i)%n] == 0)
{
c = '0' + i;
p.ch = v.ch + c;
p.ys = (v.ys * 10 + i) % n;
a[p.ys] = 1;
q.push(p);
if (p.ys == 0)
{
ans = p.ch;
Flag = 1;
break;
}
}
if (Flag == 1) break;
}
}
printf("Case %d: ", tt++);
if (Flag == 1) cout << ans << endl;
else printf("-1\n");
}
return 0;
}