hdu 1226 超级密码 bfs

本文介绍了一道关于寻找宝藏密码的编程题,通过使用同余判断方法进行剪枝优化,最终实现寻找满足特定条件的最小倍数。文章详细解析了解题思路,并提供了完整的AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Ignatius花了一个星期的时间终于找到了传说中的宝藏,宝藏被放在一个房间里,房间的门用密码锁起来了,在门旁边的墙上有一些关于密码的提示信息:
密码是一个C进制的数,并且只能由给定的M个数字构成,同时密码是一个给定十进制整数N(0<=N<=5000)的正整数倍(如果存在多个满足条件的数,那么最小的那个就是密码),如果这样的密码存在,那么当你输入它以后门将打开,如果不存在这样的密码......那就把门炸了吧.

注意:由于宝藏的历史久远,当时的系统最多只能保存500位密码.因此如果得到的密码长度大于500也不能用来开启房门,这种情况也被认为密码不存在.
 

Input

输入数据的第一行是一个整数T(1<=T<=300),表示测试数据的数量.每组测试数据的第一行是两个整数N(0<=N<=5000)和C(2<=C<=16),其中N表示的是题目描述中的给定十进制整数,C是密码的进制数.测试数据的第二行是一个整数M(1<=M<=16),它表示构成密码的数字的数量,然后是M个数字用来表示构成密码的数字.两个测试数据之间会有一个空行隔开.

注意:在给出的M个数字中,如果存在超过10的数,我们约定用A来表示10,B来表示11,C来表示12,D来表示13,E来表示14,F来表示15.我保证输入数据都是合法的.
 

Output

对于每组测试数据,如果存在要求的密码,则输出该密码,如果密码不存在,则输出"give me the bomb please".

注意:构成密码的数字不一定全部都要用上;密码有可能非常长,不要试图用一个整型变量来保存密码;我保证密码最高位不为0(除非密码本身就是0).
 

Sample Input

    
3 22 10 3 7 0 1 2 10 1 1 25 16 3 A B C
 

Sample Output

    
110 give me the bomb please CCB


题意及分析:

给一个10进制数n,m个c进制数。用m个数中的一些数组成n最小的倍数。

这里用到了这样的知识点:

此题可以用同余判断的方法来剪枝。

假如 A%X  ==  B%X  (设A<B)

那么 (A*10+Ki)%X==(B*10+Ki)%X

所以A,B之中我们只要取前面的A就行,因为题目要取最小的数,通过同余我们可以知道,A和B这两个数在末尾添加任何相同的数MOD X之后的余数都是一样的,因此对于比A大的数我们就没有必要去扩展了。B可以直接减掉。即对余数进行标记,已经出现过的余数(即当前得到的数与我之前已经得到的某个数同余),将不再扩展节点。

 

这是截取自别人的博客:http://blog.youkuaiyun.com/lenleaves/article/details/8908416

我是这样理解的:

这个题大体思路是这样的,假如k=a*c+b,k是由题目给的一些数组成的。当k%n==0时,那么k就是我们要求的数。而a又可以分解为a=a1*c+b1,以此类推。在这之前还有一点就是,k%n=((a%n)*c+b)%n。在bfs拓展数时,是按照刚才的逆过程。如果最先找到一个一个数k1%n==0,在逆序输出之前的拓展的各个数位。

将m个数从小到大排序,依次拓展新的数,这样就可以得到最小的满足条件的n的倍数。也可以看看上面博客的解释。那是相似的一道题。

AC代码:

#include
  
   
#include
   
    
#include
    
     
#include
     
      
#include
      
#include
       
         #include
        
          #include
         
           #define eps 1e-9 #define ll long long #define INF 0x3f3f3f3f using namespace std; struct node { int id,digit; //记录编号,和拓展它的前一位(用于递归输出),每一位的数值,当前数的余数 int mod,pre; }que[1000000],now,tmp; bool flag[5010]; int M,C,N,cnt,num; int a[100]; char ans[200]; void build(int k) { if(que[k].id==0) return; build(que[k].pre); if(que[k].digit<10) ans[cnt++]=que[k].digit+'0'; else ans[cnt++]=que[k].digit-10+'A'; } int bfs() { int front=0,rear=0,i; now.mod=0,now.digit=0,now.id=0,now.pre=-1; que[rear++]=now; while(front
          
           0||now.pre!=-1)) //避免首位出现0的情况 { flag[(now.mod*C+a[i])%N]=true; tmp.mod=(now.mod*C+a[i])%N; tmp.digit=a[i]; tmp.pre=now.id; tmp.id=rear; if(tmp.mod==0) { cnt=0; build(tmp.pre); if(tmp.digit<10) ans[cnt++]=tmp.digit+'0'; else ans[cnt++]=tmp.digit-10+'A'; ans[cnt]='\0'; return 0; } que[rear++]=tmp; } } return -1; } int main() { int T; char s[100]; scanf("%d",&T); while(T--) { scanf("%d%d%d",&N,&C,&M); getchar(); gets(s); int k=0; num=0; while(s[k]!='\0') //将字符串里的数字读取,数组存贮并排序 { if(s[k]==' ') k++; if('0'<=s[k]&&s[k]<='9') a[num++]=s[k++]-'0'; else a[num++]=s[k++]-'A'+10; } sort(a,a+num); //for(int i=0;i
           
            0) //最小的数大于0 printf("give me the bomb please\n"); else printf("0\n"); continue; } memset(flag,false,sizeof(flag)); int res=bfs(); if(res==-1) printf("give me the bomb please\n"); else if(strlen(ans)>500) printf("give me the bomb please\n"); else printf("%s\n",ans); } return 0; } 
           
          
         
        
       
     
    
   
  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值