poj1465:http://poj.org/problem?id=1465
题意:给你一个数n(0~4999);以及m个不同十进制的数,问有这些十进制数组成的最小的n的倍数是多少。如果有则输出,没有就输出0;
题解:此题用BFS 。。这个题好在 用 余数判重剪枝。。BFS 如果不加以剪枝,一定会搜索的情况会很庞大。所以应该用余数判重 。
为什么可以用余数判重?
A=a*N +e 即A%N =e
B= b*N+e即B%N=e
当A B mod N的余数相同时,如果先出现A 。在A 后加上一个数 i 时 , 新的数 C = 10 *a*N + 10 *e+i;同样 B后加上数 i 时 , D = 10*b*N +10*e+i; 由于C D 前边 10*a*N 和 10*b*N 都是N的倍数 ,则C D mod N 的余数都是有 10*e+i 决定的。于是 C D mod N 同余。因此 A B 同余 都添加上 i 之后 新的两个数C D也是同余的。在无论添加多少个数,新生成的两个数也是同余的。因此 在A 之后如果不出现 N的倍数 ,则在B之后也不会出现。 在A 之后出现,那B之后也会出现。 有因为要求求最小值。所以只需要搜索min(A,B)之后的 ,对于另外一个数之后就不用搜索了。因为对M个排序后,先填入的是小的值,所以 A B 先出现的值小。所以后出现的同余的数 就不用搜索了。因此可以余数判重后剪枝。。。。
1 #include<cstdio> 2 #include<stdlib.h> 3 #include<queue> 4 #include<cstring> 5 #define INF 1000000000 6 using namespace std; 7 int n,m,d[150]; //d数组用来储存m个数 8 struct point{ 9 int yu;//记录余数 10 int pre;//记录来自哪一层 11 int now; //记录当前的是哪一个d【i】; 12 }que[10000]; 13 int cmp(const void * a,const void * b){ 14 int * aa=(int *)a; 15 int * bb=(int *)b; 16 return *aa-*bb; 17 } //比较器从小到大 18 void print(int tem){ 19 if(que[tem].pre!=-1){ 20 print(que[tem].pre); 21 printf("%d",que[tem].now); 22 } 23 }//递归输出 24 int bfs(){ 25 int front=0,rear=0; 26 int flag[5010];//标记是否访问 27 que[rear].now=0; 28 que[rear].pre=-1; 29 que[rear++].yu=0; 30 memset(flag,0,sizeof(flag)); 31 while(front<rear){ 32 struct point tem; 33 tem=que[front]; 34 for(int i=0;i<m;i++){ 35 int temp=(tem.yu*10+d[i])%n; 36 if(!flag[temp] && (tem.pre!=-1 || d[i]>0)){ 37 struct point st; 38 st.now=d[i]; 39 st.yu=temp; 40 st.pre=front; 41 flag[temp]=1; 42 que[rear++]=st; 43 if(temp==0){ 44 print(rear-1); 45 printf(" "); 46 return 1; 47 } 48 } 49 } 50 front++; 51 } 52 return 0; 53 }//在大脑中一定要有完整清晰的思路。 54 int main(){ 55 int i; 56 while(scanf("%d",&n)!=EOF){ 57 scanf("%d",&m); 58 for(i=0;i<m;i++) 59 scanf("%d",&d[i]); 60 qsort(d,m,sizeof(d[0]),cmp); 61 if(n==0){ 62 printf("0 "); 63 } 64 else if(!bfs()) 65 printf("0 "); 66 } 67 }