题目链接:http://icpc.njust.edu.cn/Problem/Hdu/1226/
题目大意是:寻找一个五百位之内的C进制密码,该密码是N的正整数倍,而且只能用给定的数构成密码,求这样的密码最小是多少。思路也不难想到,密码的位数有限,我们可以通过广度优先搜索来搜索目标状态,通过已经拼接好的密码再在最后添加一位就能产生扩展后的密码,也就是层数增加一层,我们可以一层层搜索,但是五百层是绝对不可能通过不剪枝的方法就能搜完的。剪枝的条件是:对于余数相同的数,只让最小的数入队。
证明如下:
假设a=k1*n+q(0<=q<n),b=k2*n+q(0<=q<n),而且 k2>k1,(即a,b余数相同但是a大)那么再进行扩展时,t*a+c=(t*k1)*n+t*q+c,t*b=(t*k2)*n+t*q+c,此时必有t*a>t*b,而且两者模n的余数一定是相等的,如果余数都是0,那么显然t*b+c更加小,所以对于每一种余数,我们只要保存最小数的进行扩展就能保证最终第一个出现的N倍数的数是最小的密码。若选择较大的数成功搜索,则比它小的余数相同的数按照同样的步骤肯定能成为N的倍数。
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef unsigned int ui; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 #define pf printf 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 #define prime1 1e9+7 9 #define prime2 1e9+9 10 #define pi 3.14159265 11 #define lson l,mid,rt<<1 12 #define rson mid+1,r,rt<<1|1 13 #define scand(x) scanf("%llf",&x) 14 #define f(i,a,b) for(int i=a;i<=b;i++) 15 #define scan(a) scanf("%d",&a) 16 #define dbg(args) cout<<#args<<":"<<args<<endl; 17 #define inf 0x3f3f3f3f 18 #define maxn 510 19 #define maxm 5010 20 int n,m,t,c; 21 int book[20]; 22 bool vis[maxm]; 23 struct node{ 24 int a[maxn]; 25 int len;//分别保存每一位密码,密码长度 26 }; 27 int getmod(node tmp)//获取余数的函数 28 { 29 int ans=0; 30 f(i,0,tmp.len-1) 31 { 32 ans=(ans*c+tmp.a[i])%n; 33 //应用多项式的计算,由于加法和乘法对于模运算的顺序是不影响的 34 } 35 return ans; 36 } 37 node cur,ans; 38 bool flag=false; 39 void print(node tmp) 40 { 41 f(i,0,tmp.len-1) 42 { 43 if(tmp.a[i]<10)pf("%d",tmp.a[i]); 44 else pf("%c",tmp.a[i]-10+'A'); 45 } 46 putchar(' '); 47 } 48 49 void bfs() 50 { 51 queue<node>q; 52 node st; 53 st.len=0; 54 int r; 55 f(i,1,15)//首位特判,因为不能为零 56 { 57 if(book[i]) 58 { 59 st.len=1; 60 st.a[0]=i; 61 r=getmod(st); 62 if(!r) 63 { 64 flag=1; 65 ans=st; 66 return; 67 } 68 if(!vis[r]) 69 { 70 q.push(st); 71 vis[r]=1; 72 } 73 } 74 } 75 while(!q.empty()) 76 { 77 cur=q.front(); 78 q.pop(); 79 f(i,0,15) 80 { 81 if(book[i]) 82 { 83 cur.len++; 84 cur.a[cur.len-1]=i; 85 r=getmod(cur); 86 if(!r) 87 { 88 flag=1; 89 ans=cur; 90 return; 91 } 92 if(!vis[r]&&cur.len<500) 93 { 94 vis[r]=1; 95 q.push(cur); 96 } 97 cur.len--; 98 } 99 } 100 } 101 } 102 int main() 103 { 104 //freopen("input.txt","r",stdin); 105 //freopen("output.txt","w",stdout); 106 std::ios::sync_with_stdio(false); 107 scan(t); 108 while(t--) 109 { 110 mem(book,0); 111 mem(vis,false); 112 flag=false; 113 scan(n);scan(c); 114 scan(m); 115 getchar(); 116 char x[3]; 117 while(m--) 118 { 119 scanf("%s",x); 120 if(x[0]>='0'&&x[0]<='9')book[x[0]-'0']=1;//保存可访问的数 121 else book[x[0]-'A'+10]=1; 122 } 123 if(n==0) 124 { 125 if(book[0])//如果要求密码是0的倍数,那么密码就是0,要是给了0就完成,没给0不可以达成目的 126 pf("0 "); 127 else pf("give me the bomb please "); 128 } 129 else 130 { 131 bfs(); 132 if(flag) 133 { 134 print(ans); 135 } 136 else pf("give me the bomb please "); 137 } 138 } 139 return 0; 140 }