POJ 1780 Code(欧拉回路+非递归dfs)

http://poj.org/problem?id=1780

题意:
有个保险箱子是n位数字编码,当正确输入最后一位编码后就会打开(即输入任意多的数字只有最后n位数字有效)……要选择一个好的数字序列,最多只需按键10n+n-1次就可以打开保险箱子,即要找到一个数字序列包含所有的n位数一次且仅一次。序列要为字典序。

 

思路:

对于当前长度为n-1的序列,其后添加一个数字,使得添加后的序列没有在前面出现过。这样的话,以n-1位数为顶点,新增一个数后构成n位数为边,到达后n-1位数的新顶点。这样一来,就构成了一个图,我们只要不重复的经过图中所有边即可,那么这就是欧拉回路了。

在寻找路径的时候需要用dfs,但是吧,这里直接dfs是要爆栈的,所以这里必须要用非递归的方法来实现dfs,也就是要借助栈。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,int> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn = 1e5 + 5;
17 
18 int n;
19 int s,t,v;
20 int list[maxn];
21 int sta[maxn*10];
22 char ans[maxn*10];
23 
24 void search(int v, int m)
25 {
26     int w;
27     while(list[v]<10)
28     {
29         int w=v*10+list[v];
30         list[v]++;
31         sta[s++]=w;
32         v=w%m;
33     }
34 }
35 
36 int main()
37 {
38     //freopen("in.txt","r",stdin);
39     while(~scanf("%d",&n) && n)
40     {
41         if(n==1)
42         {
43             puts("0123456789");
44             continue;
45         }
46         int m=pow(10.0,(double)(n-1));
47         for(int i=0;i<m;i++)   list[i]=0;  //list【i】记录了i顶点接下来要走的边,因为是要按字典序顺序,
48                                            //所以它肯定先走添加0的,然后1,2...直到9
49 
50         s=0,t=0,v=0;
51         search(v,m);  //从起点出发会有10条边可走,先从起点出发随便走一条,当然也不是随便的...先走一下字典序小的那条路
52         while(s)  //有些顶点可能还有别的路可以走,所以继续选择顶点把该顶点剩余的未走的边走完
53         {
54             v=sta[--s]; ans[t++]=v%10+'0';
55             v/=10;
56             search(v,m);
57         }
58         for(int i=1;i<n;i++)   printf("0");
59         while(t)  printf("%c",ans[--t]);
60         printf("\n");
61     }
62     return 0;
63 }

 

posted @ 2017-07-18 15:41  Kayden_Cheung  阅读(372)  评论(0编辑  收藏  举报
//目录