/* 对于n为密码想要序列最短 那么 1234 2345 这两个一定挨着 就是说 前一个的后n-1位是后一个的前n-1位 假设n==3 我们用0-99作为点的编号建图 然后每个点连出去10条边 两个相邻点有n-1个是重复的 边的权值可用两个点计算 比如 12 23 权值为123 123 234 权值为1234 显然最后的序列是每个边记录一次 也就是跑欧拉路 对于记录下的边权 第一条输出前n-1为 上下的输出最后一位 这就是答案了 poj上没有special judge 要求字典序最小 这里建边时从9-0 就ok了 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 1000010 using namespace std; int n,m,num,head[maxn],s[maxn],len; int S[maxn],top,f[maxn],T[maxn]; struct node { int u,v,t,pre; }e[maxn*2]; void Clear() { num=len=top=0; memset(head,-1,sizeof(head)); memset(head,-1,sizeof(head)); memset(f,0,sizeof(f)); } void Add(int from,int to,int dis) { e[num].v=to; e[num].t=dis; e[num].pre=head[from]; head[from]=num++; } void Dfs(int x) { S[++top]=x;T[top]=0; while(top) { int u=S[top],falg=0,ti=T[top]; for(int i=head[u];i!=-1;i=e[i].pre) { int v=e[i].v; if(f[e[i].t])continue; falg=1;f[e[i].t]=1; S[++top]=v;T[top]=e[i].t; break; } if(!falg)s[++len]=ti,top--; } } int main() { while(scanf("%d",&n)&&n) { Clear(); if(n==1){puts("0123456789");continue;} int t=1,r=1; for(int i=1;i<n;i++)t*=10,r*=10;r/=10; for(int i=0;i<t;i++) for(int j=9;j>=0;j--) Add(i,i%r*10+j,i*10+j); Dfs(0); for(int i=1;i<=n-2;i++)printf("0"); printf("%d",s[len]/10); for(int i=len-1;i>=1;i--)printf("%d",s[i]%10); printf("\n"); } }
时间: 2024-10-10 01:57:33