题意:一个密码位数不超过500,且最高位不为0,它是一个由m个数字组成的c进制数,并且密码是N的整数倍里最小那个,将其输出,如果不存在输出give me the bomb please。
思路:从高位开始,每添加一位,则扩展m个状态,判断每个状态代表的数字能否整除n,如果能就是符合题意的密码,不能将这个余数标记,是个强剪枝,因为同余的数,后面一位再添加相同的数还是同余,所以访问一次就行了,如果状态跑完(密码的长度>500),都没找到,则说明不存在。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
bool num[17];
int N,C;
char s[10];
int vis[6000];
struct node
{
int s[550];
int len;
};
int mod(node a)
{
int temp=0;
for(int i=0;i<a.len;i++)
{
temp=(temp*C+a.s[i])%N;
}
return temp;
}
void print(node a)
{
for(int i=0;i<a.len;i++)
{
if(a.s[i]>=0&&a.s[i]<=9)printf("%d",a.s[i]);
else printf("%c",a.s[i]-10+'A');
}
printf("\n");
}
bool bfs()
{
memset(vis,0,sizeof(vis));
queue<node> q;
node a;
a.len=0;
for(int i=1;i<16;i++)//特判第一位
{
if(num[i])
{
a.s[0]=i;
a.len=1;
int r = mod(a);
if(!r)
{
print(a);
return 1;
}
else if(!vis[r])
{
vis[r]=1;
q.push(a);
}
}
}
while(!q.empty())
{
node a = q.front();q.pop();
for(int i=0;i<16;i++)
{
if(num[i])
{
a.s[a.len]=i;
a.len++;
int r = mod(a);
if(!r)
{
print(a);
return 1;
}
else if(!vis[r]&&a.len<499)
{
vis[r]=1;
q.push(a);
}
a.len--;//重复试探第len位,此len与压入栈中的a.len不同
}
}
}
return 0;
}
int main()
{
int T;
//freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--)
{
int M;
memset(num,0,sizeof(num));
scanf("%d%d%d",&N,&C,&M);
for(int i=0;i<M;i++)
{
scanf("%s",s);
if(s[0]>='0'&&s[0]<='9')
num[s[0]-'0']=1;
else
num[s[0]+10-'A']=1;
}
if(N==0)
{
if(num[0])
printf("0\n");
else
printf("give me the bomb please\n");
}
else
{
int flag=bfs();
if(!flag)
printf("give me the bomb please\n");
}
}
}