hdu 1226 超级密码(bfs+余数判重)

题意:略过

分析:用m个数字组成一个能够被n整除的c进制数的最小值,实际上本题的关键就在于这个最小值上。

    首先确定我们的思路是从小到大寻找。先查看一位数,即查看着m个数字是否能被n整除;若不能,就查看任意可能的两位数组合...可是如此一来,预算量太大。于是我们考虑是否存在冗余量。

    已知A,B两个数(A<B),A%n==x,B%n==x,我们称其为同余,那么以它们为基础的相同变换(从一位数到两位数):A*c+C,B*c+C,这两个数同样同余,(A*c+C)%n==((A*c)%n+C%n)%n==(((A%n)*c)%n+C%n)%n==(((B%n)*c)%n+C%n)%n==(B*c+C)%n。所以,若我们能够在由 B 为基础扩展出的数字中找到一个能被 n 整除的值,那经过相同的变换,由 A 扩展出的数字一定也能被 n 整除,并且一定更小。

    根据以上推论,我们知道一旦我们发现一个余数为x的数字(因为是从小到大查找,该数字必然是最小值),那么之后凡是余数为x的数字都可以忽略不计。由于题目中给出的数字n<=5000,所以我们用bfs搜索,最多只需查找5000个状态,计算量大幅减少。

错误:n==0,当且仅当m个数字中含有0,答案为0;否则,无解。

注意:本题是pku 1465的延伸——由10进制数改为任意进制数,但是时限过于宽泛(也可能是数据太水了),导致用这道题的思路解题严重超时。

 

这是最初的思路,把每一个扩展的数字都加入队列,运算量太大。

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 const int MAXN=5555;
  9 const int N=22;
 10 
 11 struct Node{
 12     char s[MAXN];
 13     int len;
 14 };
 15 
 16 int md[MAXN];
 17 int num[N];
 18 int n,c,m;
 19 queue<Node>q;
 20 
 21 int Num(char ch)
 22 {
 23     if(ch>='0'&&ch<='9')
 24         return ch-'0';
 25     return ch-'A'+10;
 26 }
 27 
 28 int qmod(Node e)
 29 {
 30     int cnt=0;
 31     for(int i=0;i<e.len;i++)
 32         cnt=(cnt*c+e.s[i])%n;
 33     return cnt;
 34 }
 35 
 36 void print(Node e)
 37 {
 38     for(int i=0;i<e.len;i++)
 39         if(e.s[i]>=0&&e.s[i]<=9)
 40             printf("%d",e.s[i]);
 41         else
 42             printf("%c",e.s[i]-10+'A');
 43     printf("\n");
 44 }
 45 
 46 int bfs()
 47 {
 48     memset(md,0,sizeof(md));
 49     while(!q.empty())
 50         q.pop();
 51 
 52     Node e;
 53     for(int i=1;i<16;i++)
 54     {
 55         if(num[i]){
 56             e.s[0]=i;
 57             e.len=1;
 58             int cnt=qmod(e);
 59             if(cnt==0){
 60                 print(e);
 61                 return 1;
 62             }
 63             if(!md[cnt]){
 64                 q.push(e);
 65                 md[cnt]=1;
 66             }
 67         }
 68     }
 69     while(!q.empty())
 70     {
 71         e=q.front();q.pop();
 72         /*
 73         for(int i=0;i<e.len;i++)
 74             printf("%d",e.s[i]);
 75         printf("\n");
 76         */
 77         for(int i=0;i<16;i++)
 78         {
 79             if(num[i]){
 80                 e.s[e.len]=i;
 81                 e.len++;
 82                 if(e.len>=500)
 83                     return -1;
 84 
 85                 int cnt=qmod(e);
 86                 if(cnt==0){
 87                     print(e);
 88                     return 1;
 89                 }
 90                 if(!md[cnt]){
 91                     q.push(e);
 92                     md[cnt]=1;
 93                 }
 94                 e.len--;
 95             }
 96         }
 97     }
 98     //printf("??\n");
 99     return -1;
100 }
101 
102 int main()
103 {
104     int T;
105     scanf("%d",&T);
106     while(T--)
107     {
108         scanf("%d%d%d",&n,&c,&m);
109 
110         memset(num,0,sizeof(num));
111         for(int i=0;i<m;i++)
112         {
113             char x[2];
114             scanf("%s",x);
115             num[Num(x[0])]=1;
116         }
117         if(n==0)
118             if(num[0])
119                 printf("0\n");
120             else
121                 printf("give me the bomb please\n");
122         else{
123             int ans=bfs();
124             if(ans==-1)
125                 printf("give me the bomb please\n");
126         }
127     }
128     return 0;
129 }
View Code

做完pku 1465 后,又回过头来做,忘记加密码长度的限制 len<=500,狠狠的wa了一发

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 const int MAXN=5010;
  9 const int N=16;
 10 
 11 struct Node{
 12     int pre;
 13     int r;
 14     int d;
 15     int len;
 16 };
 17 
 18 int vis[MAXN];
 19 int num[N];
 20 int n,c,m;
 21 Node q[MAXN];
 22 
 23 int Num(char ch)
 24 {
 25     if('0'<=ch&&ch<='9')
 26         return ch-'0';
 27     return ch-'A'+10;
 28 }
 29 
 30 void print(int x)
 31 {
 32     if(q[x].pre==-1)
 33         return ;
 34     print(q[x].pre);
 35     if(q[x].d>=10)
 36         printf("%c",q[x].d-10+'A');
 37     else
 38         printf("%d",q[x].d);
 39 }
 40 
 41 int bfs()
 42 {
 43     memset(vis,0,sizeof(vis));
 44     int dl,dr;
 45     dl=dr=0;
 46     Node u,v;
 47     u.pre=-1;
 48     u.d=0;
 49     u.r=0;
 50     u.len=0;
 51     q[dr++]=u;
 52     vis[0]=1;
 53 
 54     int ok=0;
 55     while(dl<dr)
 56     {
 57         u=q[dl++];
 58         for(int i=0;i<m;i++)
 59         {
 60             int r=u.r*c+num[i];
 61             if(r>=n&&r%n==0){
 62                 print(dl-1);
 63                 if(num[i]>=10)
 64                     printf("%c\n",num[i]-10+'A');
 65                 else
 66                     printf("%d\n",num[i]);
 67                 return 1;
 68             }
 69             r=r%n;
 70             if(!vis[r]){
 71                 vis[r]=1;
 72                 v.r=r;
 73                 v.d=num[i];
 74                 v.pre=dl-1;
 75                 v.len=u.len+1;
 76                 if(v.len>500)
 77                     return -1;
 78                 q[dr++]=v;
 79             }
 80         }
 81     }
 82     return -1;
 83 }
 84 
 85 int main()
 86 {
 87     int T;
 88     scanf("%d",&T);
 89     while(T--)
 90     {
 91         scanf("%d%d%d",&n,&c,&m);
 92         memset(num,-1,sizeof(num));
 93         for(int i=0;i<m;i++)
 94         {
 95             char s[2];
 96             scanf("%s",s);
 97             num[i]=Num(s[0]);
 98         }
 99         sort(num,num+m);
100 
101         if(n==0)
102             if(num[0]==0)
103                 printf("0\n");
104             else
105                 printf("give me the bomb please\n");
106         else{
107             int ans=bfs();
108             if(ans==-1)
109                 printf("give me the bomb please\n");
110         }
111     }
112     return 0;
113 }
View Code

 

转载于:https://www.cnblogs.com/zstu-abc/p/3348660.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值