http://acm.hdu.edu.cn/showproblem.php?pid=4474
比赛的时候犯的错,刚刚写的时候又犯了一次,囧。。。。
题目意思
输入n,m 和 m个字符(数字),要求找到一个最小的n的倍数,不含有给出的m个数字。如果不存在则输出-1
其实大家应该对这题不会陌生,本场成都的网赛就出现过一个类似的:http://acm.hdu.edu.cn/showproblem.php?pid=4294
比较简单的bfs,利用所有能用的数字进行bfs即可。
每个节点记录三个值
c:末尾的那个数字
m:这个节点所代表的数字对n取模的值
f:父节点
对于一个节点,如果在其后面加一个数字i,那么新的m值=(m*10 + i)%n
显然,如果答案存在,那么我们第一个找到的m==0的节点就是答案,然后再用一个递归逆序输出就好。
可以发现,新节点的m的值只与父节点的m值有关,所以,对于相同的m,只有第一个出现m的节点是有用的。
本题一个坑就是假如能使用的数字非常少,则答案可能很大,超过longlong的表示范围。不过这个如果做过成都网赛那道题,应该会立马有感觉。
当然,本题直接用字符串记录数字也是可以的,就不用递归输出了。因为用过的节点也要保留,所以没有使用STL的队列。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 struct{ 5 int m,f; 6 char c; 7 }d[10010],tmp; 8 int n,m,l,r; 9 bool h[10010],k[10]; 10 void out(int x){ 11 if(x==-1)return; 12 out(d[x].f); 13 putchar(d[x].c); 14 } 15 int main() 16 { 17 int C=0; 18 while (~scanf("%d%d",&n,&m)){ 19 printf("Case %d: ",++C); 20 memset(h,true,sizeof(h)); 21 memset(k,true,sizeof(k)); 22 l=r=0; 23 24 for(int i=0;i<m;i++){ 25 int x; 26 scanf("%d",&x); 27 k[x]=0; 28 } 29 30 int ans=-1; 31 for(int i=1;i<10;i++)if(k[i]){ 32 tmp.c=i+'0'; 33 h[tmp.m=i%n]=false; 34 tmp.f=-1; 35 d[r++]=tmp; 36 if(tmp.m==0){ 37 ans=r-1; 38 break; 39 } 40 } 41 while(l<r && ans==-1){ 42 for(int i=0;i<10;i++)if(k[i]){ 43 tmp.c=i+'0'; 44 tmp.m=(d[l].m*10 + i)%n; 45 if(h[tmp.m]){ 46 h[tmp.m]=false; 47 tmp.f=l; 48 d[r++]=tmp; 49 if(tmp.m==0){ 50 ans=r-1; 51 break; 52 } 53 } 54 } 55 l++; 56 } 57 if(ans==-1) puts("-1"); 58 else{ 59 out(ans); 60 putchar('\n'); 61 } 62 } 63 return 0; 64 }