hdu 1226 超级密码bfs

来源:互联网 发布:淘宝客返利机器人 编辑:程序博客网 时间:2024/06/07 02:01
Online JudgeOnline ExerciseOnline TeachingOnline ContestsExercise AuthorF.A.Q
Hand In Hand
Online Acmers
Forum | Discuss
Statistical Charts
Problem Archive
Realtime Judge Status
Authors Ranklist
 
     C/C++/Java Exams     
ACM Steps
Go to Job
Contest LiveCast
ICPC@China
STD Contests 
VIP Contests 
Virtual Contests 
    DIY | Web-DIY beta
Recent Contests
Author 53150
Mail Mail 0(0)
Control Panel Control Panel 
Sign Out Sign Out
杭电第12届校赛账号信息(3教3楼机房 3月17日12:00~16:00)
***来加好友吧***,"HDOJ人人网公共主页"已经开通~

超级密码

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 929    Accepted Submission(s): 302


Problem 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
322 1037 0 12 101125 163A B C
 

Sample Output
110give me the bomb pleaseCCB
Hint
Hint
Huge input, scanf is recommended.
 

Author
Ignatius.L
 

Source
杭州电子科技大学第三届程序设计大赛
 

Recommend
Ignatius.L
 

Statistic | Submit | Discuss

看了这个解题报告之后http://ip96cns.blog.163.com/blog/static/1700951922011122113332389/  主要是余数的判重

这题目仍然是增加一位数求余数......

在POJ上有一道类似题目.给一个数字,求其只由0或1组成的某个倍数..原理相同....哈哈我当时没优化...这次学乖了优化了才过......

基本原理:

r= k (mod c)則 (k*p+a)(mod c)=(r*p+a)(mod c)

形式证明.....r=k(mod c)-> k= q*c+r -> (k*p+a)=((q*c+r)*p+a)=p*q*c+p*r+a -> (k*p+a) (mod c) = (r*p+a) (mod c)

(注:由于p*q*c中含有因子c,所以取模后=0.........)

优化原理:(据说理论基础是"鸽巢原理"....个人无法明白....如果有人能解释感激不尽....)

随便说下吧....

如果某个数值序列的余数为r.....如果某个余数已经被构造过...那么后面得到的一定是与原来构造过的余数序列相同的序列...意思是..这是一个循环(周期函数?....扯远了...)..而由BFS的性质.最短的一定是最先被构造出来的..所以.....先到先得!(每一位使用什么数字都是不变的哦.....就是在同一个数值集合内...).

那么之前那些高位的数字呢?...不用管数值序列了,只看余数......既然知道余数是r,如果这个余数已经出现过.那么接下来构造的序列的余数序列 r1,r2,r3,.....一定是之前重复过的.而纠缠这些相同的还有啥么意义呢....咱们要余数为0的....

所以...终于到结论了....

只要某种余数曾经出现过.那么这种余数就不需要再出现.....这个东西表达在代码上不会太困难,因为题目已经给了数值范围<=5000.所以.....完了

顺便提示:没有优化会死的很惨烈很惨烈....

-------

关于题目的....

对于0什么时候可能出现呢?....

一个数n的倍数一定大于等于n...(题目除0了..),但是余数为0除了0之外,至少都是大于等于n....这不需要特别判定

然而当题目给的某数字为0,并且单纯一位的值存在0,才为0...否则..不存在这样的数值序列.....

为什么一个非0值 ...1,2或者其他...不能成为0的倍数呢?...不得知.....这看来还得看测试数据.....

我也搞不懂了,看了别人的代码才知道....幸亏有人分享代码哎...否则又要WA一辈子了.....





#include<stdio.h>#include<algorithm>using namespace std;#define N 100000/*只是01串那道题的强化版本而已,要求长度小于500,N<5000,明显要优化,对余数的判重。*/int c[17];int pre[N],prec[N];int que[N];int cc,n,m;int bfs(){    int i=0,j,k,t,r,vis[N]={0};    int front=0,rear=0;    if(c[0]==0)    {        i=1;        rear=1;        front=1;        pre[0]=-1;        prec[0]=0;    }    if(n==0)    {        if(c[0]==0)            return 0;        return -1;    }    for(;rear<m;++i,++rear)    {        que[rear]=c[i]%n;        prec[i]=c[i];        pre[i]=-1;        vis[que[rear]]=1;        if(que[rear]==0)            return i;    }    while(front<rear)    {        r=que[front];        if(vis[r]==500)            return -1;        k=front++;        for(j=0;j<m;++j)        {            t=(r*cc+c[j])%n;            if(!vis[t])            {                vis[t]=vis[r]+1;                prec[i]=c[j];                pre[i]=k;                if(t==0)                    return i;                i++;                que[rear++]=t;            }        }    }    return -1;}void solve(){    int k=bfs();    if(k==-1)    {        printf("give me the bomb please\n");        return ;    }    char str[N];    int i=0;    for(;k!=-1;++i,k=pre[k])    {        if(prec[k]<10)            str[i]=char(prec[k]+'0');        else            str[i]=char(prec[k]-10+'A');    }    --i;    while(i>0)        printf("%c",str[i--]);    printf("%c\n",str[i]);}int main(){    int i,t;    char s[2];    scanf("%d",&t);    while(t--)    {        scanf("%d%d%d",&n,&cc,&m);        for(i=0;i<m;++i)        {            scanf("%s",s);            if(s[0]<='9')                c[i]=s[0]-'0';            else                c[i]=s[0]-'A'+10;        }        sort(c,c+m);        solve();    }    return 0;}/**/











原创粉丝点击