题目大意
有一个很水的密码系统,你只需要一阵乱按,按到的最后n位数是对的,锁就打开了。找一个最短的,字典序最小的序列,包含n位数的所有情况。(那个这个序列去凑密码就一定能开)
题目的提示:序列一定是
10n+n−1
长度的。
题解
本人很弱,看的其他大神的题解。
建图:
所有n-1位数作为点,如果另一个数的前n-2位与这个数的后n-2位相同,则连一条边。
如n=4,abc->bcd,这条边表示abcd可以被表示出来。
欧拉回路保证每条边只走一次,所以每个n位数只会出现一次。
因为点数过于多,所以需要欧拉回路的循环实现。
代码
#include<cstdio>
#include<cstring>
const int MAXN=100010;
const int pow10[10]={1,10,100,1000,10000,100000,1000000};
int sta[MAXN*10],top,pt;
char path[MAXN*10];
bool vis[MAXN*10];
int n;
void dfs(int id)
{
int x;
for(int i=0;i<10;i++)
{
x=id*10+i;
if(vis[x])
continue;
vis[x]=true;
dfs(x%pow10[n-1]);
}
path[++top]=id;
}
void find_circle(int S)
{
int id=S,x;
bool flag=true;
while(flag)
{
flag=false;
sta[++top]=id;
for(int i=0;i<10;i++)
{
x=id*10+i;
if(vis[x])
continue;
vis[x]=true;
flag=true;
id=x%pow10[n-1];
break;
}
}
top--;
}
void euler()
{
find_circle(0);
int temp;
while(top)
{
temp=sta[top];
top--;
path[++pt]=temp%10;
find_circle(temp);
}
}
int main()
{
while(true)
{
top=0;
pt=0;
memset(vis,0,sizeof vis);
scanf("%d",&n);
if(n==0)
break;
if(n==1)
{
printf("0123456789\n");
continue;
}
euler();
for(int i=1;i<n;i++)
printf("0");
for(int i=pt-1;i>0;i--)
printf("%d",path[i]);
puts("0");
}
return 0;
}