码迷,mamicode.com
首页 > 其他好文 > 详细

POJ1780-Code(欧拉回路)

时间:2016-08-11 00:34:25      阅读:121      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:poj1780-Code

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

题解:首先明白为什么是最多只需按键10n+n-1次。n位数有10n 种编码方案,要一个数字序列包含10n 组n位数且序列最短,只可能是每组数出现一次且仅一次,且前一组数的后n-1位与后一组数的前n-1位相同,10n组数各取一位,再加上最后一组数的n-1位,总共10n +n-1位,如下所示:

第一组:d1 d2 d3…dn

第二组:     d2 d3 d4…d(n+1)

第10n组:…d(10n+n-3) d(10n+n-2) d(10n+n-1)

然后,把n-1位看成一个图中顶点,将n-1位后加一个数字(0~9)的序列看成一条边,共10n-1个顶点,10n条边,且每条边都不相同,所以这10n组不同的n位数对应图中的一个 欧拉通路。(怎么想过来的呢,你仔细看题目都提示了:题中说,保险箱始终处于10n-1种内部状态之一,假如正确编码为4567,”开锁状态“就是456,如果再输入7就开锁了,如果输入8就切换到新的状态568,然后就想转化到图上来了,把内部状态(n-1位的序列)看成顶点咯。要求解的序列最短,就是从一个顶点出发不重复地遍历所有边到达终点,这不就是赤裸裸的欧拉回路么0.0+)

注意,该题直接用递归的方法会导致栈溢出,所以要显式地用栈来实现。存储结果时优先存较大值,这样对结果栈逆序输出时就是按字典序排列啦。

代码实现:

#include<cstdio>
const int N=1e5;
int node[N],stack[10*N];
char ans[10*N];//结果栈
int s,a;
int m;
void Search(int v){//将当前顶点延伸
    int w;
    while(node[v]<10){//可以在v(n-1位的序列)后加0~9构成10条边
        w=10*v+node[v];
        node[v]++;
        stack[s++]=w;
        v=w%m;
    }
}
int main(){
    int n,i,w;
    while(scanf("%d",&n)&&n!=0){
        if(n==1){
            printf("0123456789\n");
            continue;
        }
        s=a=w=0;
        m=1;
        for(i=0;i<n-1;++i) m*=10;
        for(i=0;i<m;++i) node[i]=0;
        Search(0);
        while(s){
            w=stack[--s];
            ans[a++]=w%10+0;
            Search(w/10);
        }
        for(i=1;i<n;++i) printf("0");
        while(a) printf("%c",ans[--a]);
        printf("\n");
    }
    return 0;
}

POJ1780-Code(欧拉回路)

标签:

原文地址:http://www.cnblogs.com/GraceSkyer/p/5759348.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!