POJ--1465--Multiple【BFS+同余定理】

该博客介绍了一道POJ题目1465的解题思路,主要利用广度优先搜索(BFS)结合同余定理来寻找最小的n倍数。通过排序优化和同余定理的剪枝策略避免了无效计算,确保在n的范围内(0-4999)有效搜索,同时注意n为0的特殊情况及避免使用STL queue导致超时。
摘要由CSDN通过智能技术生成

链接:http://poj.org/problem?id=1465

题意:给一个数字n,和m个数字,找一个由这些数字组成的最小的n的倍数,如果不存在输出0。


思路:这题怎么想都想不到bfs上去,看了别人的解题报告,其实是用bfs来枚举,但是加了一个牛逼的剪枝:同余。即如果A%X==B%X,则(A*10+K)%X==(B*10+K)%X。

我们枚举m中每一个数字做这个K,实际上是枚举了一个数,B*10是之前枚举的数字,如果这个数%X得到的值之前已经得到过,则没必要再往下计算,因为根据同余定理剩下的枚举值和之前的枚举值得到的余数肯定相同,所以没必要再计算。这个剪枝保证了即使一直没找到最小倍数也不至于把数字算到无穷大去,因为n的范围为[0,4999],所以最多只会处理它5000次余数,当余数为0就找到了答案。

为了使得到的答案最小,先对m个数字排序。


细节:n==0时需要特判,X%0会RE出翔。不能用stl的queue,会TLE。


#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 500100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct node{
    int mod,num,father;
    int id;
}a[20000];
int n,m,cnt,tot;
int flag[5010],b[5010],ans[50010],ff;
void bfs(){
    int i,j;
    int front = 0, rear = 1;
    node t1,t2;
    a[front].mod = 0;
    a[front].num = 0;
    a[front].father = -1;
    while(front<rear){
        t1 = a[front];
        for(i=0;i<m;i++){
            if(!flag[(t1.mod*10+b[i])%n]&&(t1.father!=-1||b[i]!=0)){
                flag[(t1.mod*10+b[i])%n] = 1;
                a[rear].mod = (t1.mod*10+b[i])%n;
                a[rear].num = b[i];
                a[rear].father = front;
                if(a[rear].mod==0){
                    node temp = a[rear];
                    ans[tot++] = b[i];
                    while(1){
                        temp = a[temp.father];
                        if(temp.father==-1) break;
                        ans[tot++] = temp.num;
                    }
                    return ;
                }
                rear++;
            }
        }
        front++;
    }
    ff = 1;
}
int main(){
    int i,j;
    while(scanf("%d",&n)!=EOF){
        ff = tot = cnt = 0;
        memset(flag,0,sizeof(flag));
        scanf("%d",&m);
        for(i=0;i<m;i++){
            scanf("%d",&b[i]);
        }
        sort(b,b+m);
        if(n==0){
            puts("0");
            continue;
        }
        bfs();
        if(ff){
            puts("0");
            continue;
        }
        for(i=tot-1;i>=0;i--){
            printf("%d",ans[i]);
        }
        puts("");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值