hdu 1226 超级密码bfs

F.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
        
        
        
        
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
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;
}
/*

*/











你可能感兴趣的:(c,优化,测试,input,IM,output)