题意:求用m个数字(0-9)组成的n的倍数最小的那个。
分析:bfs从前往后搜索每位数字的情况,还用到了同余定理剪枝,举个例子,n=12时,搜索到13,加入队列,接着在后面又搜到25,请注意,25%12==13%12,假如25也要加入队列的话,当两数在后面加上相同数字,余数将一直相同,254%12==134%12,知道这一点,接下来,当25*****%12==13*****%12==0时,取最小13的串,也就是说25的结果一定不如13更优,干脆不搜,直接剪掉。做法:done[]存余数的出现情况(是否出现过)
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN=25;
int done[5005],n,m;
int da[13];
struct node
{
int key,pre,yu;
node(int k=0,int y=0,int p=0)
{
key=k;pre=p;yu=y;
}
}q[10000];
void showpath(int id)
{
if(q[id].pre==-1)return ;
showpath(q[id].pre);
printf("%d",q[id].key);
}
bool bfs()
{
memset(done,0,sizeof done);
int st=0,en=0;
q[en++]=node(0,0,-1);
while(st<en)
{
node x=q[st++];
for(int i=0;i<m;i++)
{
if(x.yu==0&&da[i]==0)continue;//第一个加入队列的0需要处理
int curyu=(x.yu*10+da[i])%n;
if(done[curyu])continue;//剪掉余数相同的
if(curyu==0)
{
showpath(st-1);
printf("%d\n",da[i]);
return 1;
}
done[curyu]=1;
q[en++]=node(da[i],curyu,st-1);
}
}
return 0;
}
int main()
{
while(~scanf("%d",&n))
{
scanf("%d",&m);
for(int i=0;i<m;i++)
scanf("%d",&da[i]);
if(n==0)
{
printf("0\n");
continue;
}
sort(da,da+m);
if(!bfs())printf("0\n");
}
return 0;
}

该博客详细介绍了如何利用同余定理和广度优先搜索(BFS)解决ZOJ 1136问题。博主通过举例解释了在搜索过程中如何进行剪枝,即当遇到某个数n(如25),如果n%12与已存在的13%12相等,那么后续搜索中可以避免重复计算,因为它们在后续添加相同数字后会有相同的余数。通过done[]数组记录每个余数值是否已出现,从而提高效率,找到满足条件的最小数字组合。

1451

被折叠的 条评论
为什么被折叠?



