HDU4474_Yet Another Multiple Problem

题意很简单,要你用一些数字,组成一个数的倍数,且那个数最小。

比赛的时候没能做出来,深坑啊。

其实我只想说我以前就做过这种类型的题目了,诶。

题目的解法是数位宽搜

首先把可用的数位提取出来,从小到大一个一个放到后面去。这样保证了出现的数字一定是最小的。

同时记录出现过的余数的情况,因为同一个余数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\n");
24         else printf("-1\n");
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("\n");
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\n");
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 }

 

posted @ 2013-11-01 20:12  092000  阅读(324)  评论(0编辑  收藏  举报