zoj 1136(同余+bfs)

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

题意:求用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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值