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(" "); 61 } 62 return 0; 63 }