题意很简单,要你用一些数字,组成一个数的倍数,且那个数最小。
比赛的时候没能做出来,深坑啊。
其实我只想说我以前就做过这种类型的题目了,诶。
题目的解法是数位宽搜。
首先把可用的数位提取出来,从小到大一个一个放到后面去。这样保证了出现的数字一定是最小的。
同时记录出现过的余数的情况,因为同一个余数k*10+ai再对n取余的数是相同的,所以对于同一个余数我们不需要走两遍,这样就保证了搜索的时间复杂度为O(n)。
我们只要对于每一个状态,直接枚举可选择的数字放在他们后面,直到找到一个余数为0的就可以停止了。
总的时间复杂度为O(n*10),因为后面最多可能有10个数可以放上面嘛。。。。
对于深搜的每一个状态只要用一个数字和一个前趋节点就可以了,输出的时候递归输出,因为每一个状态都是由前面的状态推过来的嘛。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define maxn 10010 5 using namespace std; 6 7 int pre[maxn],s[maxn]; 8 char q[maxn]; 9 bool res[maxn]; 10 bool b[10]; 11 int a[10],N,n,m,k,t1,t2,cur; 12 13 void output(int pos) 14 { 15 if (pre[pos]>0) output(pre[pos]); 16 printf("%d",(int)q[pos]); 17 } 18 19 void bfs() 20 { 21 if (n==0) 22 { 23 if (b[0]) printf("0 "); 24 else printf("-1 "); 25 return; 26 } 27 t1=t2=0; 28 memset(res,false,sizeof res); 29 for (int i=1; i<=9; i++) 30 if (b[i]) q[++t2]=i,pre[t2]=0,s[t2]=i%n,res[i%n]=true; 31 while (t1<t2) 32 { 33 if (s[++t1]==0) 34 { 35 output(t1); 36 printf(" "); 37 return; 38 } 39 for (int i=1; i<=N; i++) 40 if (res[(s[t1]*10+a[i])%n]==false) 41 { 42 t2++; 43 s[t2]=(s[t1]*10+a[i])%n; 44 res[s[t2]]=true; 45 q[t2]=a[i]; 46 pre[t2]=t1; 47 } 48 } 49 printf("-1 "); 50 } 51 52 int main() 53 { 54 int cas=0; 55 while (scanf("%d%d",&n,&m)!=EOF) 56 { 57 for (int i=0; i<=9; i++) b[i]=true; 58 N=0; 59 while (m--) scanf("%d",&k),b[k]=false; 60 for (int i=0; i<=9; i++) if (b[i]) a[++N]=i; 61 printf("Case %d: ",++cas); 62 bfs(); 63 } 64 return 0; 65 }