题意:输入n和m,接着输入m个十进制的数字,求最小的数ans,使得ans是n的倍数(除了0),且ans中不包括输入的十进制数字。不存在输出-1.
题解:这是一道广搜题,先找出所有可以组合ans的数字,然后就是按位枚举所有的组合(从长度为1的开始)。需要用同余剪枝,若a<b&&a%n==b%n,则之后枚举的是a=10*a+i和b=10*b+i,余数必定相同,且a<b。当出现a%n=0,b%n=0时,ans=a。所以用vis数组标记余数进行剪枝,单次复杂度最坏也只是n次。之后结果可能很大,所以不能直接用int来存,可以建个前驱标志用于输出,也可以建int数组(不过,应该不够吧),我是用string来存的。
耗时:3000MS/20000MS
#include <cstdio>
#include <cstring>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e4+10;
int vis[maxn];
int c[11];
int n,m;
string str[11]={"0","1","2","3","4","5","6","7","8","9"};
struct node{
int a;
string s;
};
queue<node>q;
void bfs()
{
while(!q.empty())q.pop();
memset(vis,0,sizeof(vis));
int i,j,k,p;
node e,u,v;
for(i=1;i<=9;i++)if(!c[i]){
if(vis[i%n])continue;
vis[i%n]=1;
e.a=i%n;
e.s=str[i];
q.push(e);
}
while(!q.empty())
{
e=q.front();
if(e.a==0)break;//这里放pop()前,不然e是队列中的最后一个就要倒霉了。。
q.pop();
for(i=0;i<=9;i++)if(!c[i]){
p=(e.a*10+i)%n;
if(vis[p])continue;
vis[p]=1;
u.a=p;
u.s=e.s+str[i];
q.push(u);
}
}
if(!q.empty())
{
cout<<e.s<<endl;
}
else
printf("-1\n");
}
int main()
{
int tt=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
int i,j,k,a;
memset(c,0,sizeof(c));
for(i=0;i<m;i++)
{
scanf("%d",&a);
c[a]++;//可能重复哦。。
}
printf("Case %d: ",++tt);
bfs();
}
return 0;
}