题意:
1.提供密码的位数。
2.密码的输入可以一直保持,取后n位作为密码。如果密码正确则开锁。
3.设计一种方法使得在输入最少的情况下破译。(即保证每个密码只输入一次)
4.输出输入的数字的序列。
思路:
去密码的前n-1位作为状态节点,将n位数密码作为边。建造有向图。
显然,每个点的入度和出度都为10,则一定存在欧拉回路。
利用简单DFS寻找欧拉回路。
(这题好像是要求输出字典序最小的序列)
DFS应该不难写,但是这题如果直接递归会爆栈。所以需要手工用栈模拟递归的过程...
屌丝看了大神的关于递归定义的博客才对递归有了更深刻的理解...
博客地址:http://www.tuicool.com/articles/BrIVz2
==以前lz只是把递归当作快速插入代码的东西来用==
代码:
#include<stdio.h> #include<string.h> int n,e,tmpe,s; bool out[1000000][11]; int road[1000050]; int mypos[1000050]; int pos[1000050]; void solve() { int load=1; bool needop=1; int tmpn=1; memset(out,1,sizeof(out)); memset(mypos,0,sizeof(mypos)); pos[1]=0; s=1; e=1; tmpe=1; for(int i=1; i<=n; i++) { e*=10; } tmpe=e/100; while(s) { if(load==1) { mypos[s]=0; load=0; continue; } else if(load==-1) { out[pos[s]][mypos[s]-1]=1; load=0; continue; } else { if(mypos[s]==10) { s--; load=-1; continue; } else if(!out[pos[s]][mypos[s]]) { mypos[s]++; load=0; continue; } else { load=1; int tmp=(pos[s]-pos[s]/tmpe*tmpe)*10+mypos[s]; road[s]=pos[s]*10+mypos[s]; out[pos[s]][mypos[s]]=0; mypos[s]++; s++; pos[s]=tmp; } } if(s>e) break; } for(int i=1;i<n;i++) printf("0"); for(int i=1;i<=e;i++) { printf("%d",road[i]%10); } printf("\n"); } int main() { scanf("%d",&n); while(n) { if(n==1) printf("0123456789\n"); else solve(); scanf("%d",&n); } }
下面是直接递归的代码:
#include<stdio.h> #include<string.h> int n,e,tmpe; bool out[1000000][11]; bool in[1000000][11]; bool vis[1000000]; int road[1000050]; int num; bool dfs(int pos,int nn) { if(nn==e-1) return 1; for(int i=0;i<10;i++) { if(out[pos][i]) { out[pos][i]=0; int tmp=(pos-pos/tmpe*tmpe)*10+i; road[nn]=pos*10+i; if(dfs(tmp,nn+1)) return 1; out[pos][i]=1; } } return 0; } void solve() { memset(in,1,sizeof(in)); memset(out,1,sizeof(out)); memset(vis,0,sizeof(vis)); e=1; tmpe=1; for(int i=1;i<=n;i++) { e*=10; } tmpe=e/100; dfs(0,0); for(int i=0;i<e-1;i++) { printf("%d\n",road[i]); } } int main() { scanf("%d",&n); while(n) { if(n==1) printf("0123456789\n"); else solve(); scanf("%d",&n); } }
时间: 2024-10-12 14:20:30