POJ1780-Code(欧拉回路)

题目链接: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;
}
时间: 2024-10-11 23:12:16

POJ1780-Code(欧拉回路)的相关文章

poj1780 code 欧拉回路

题目链接: poj1780 题意: KEY 公司开发出一种新的保险箱.要打开保险箱,不需要钥匙,但需要输入一个正确的.由n 位数字组成的编码.这种保险箱有几种类型,从给小孩子玩的玩具(2 位数字编码)到军用型的保险箱(6 位数字编码).当正确地输入最后一位编码后,保险箱就立刻打开了.保险箱上没有"确定"键.当你输入超过n 位数字,则只有最后n 位数字有效.例如,对一种4 位数字编码的型号,如果正确的编码为4567,你想输入的编码为1234567890,则保险箱的门会在你输入数字7 后马

POJ 1780 Code 欧拉回路+手写栈DFS

和西安邀请赛那道题题目差不多,现在终于会手写栈了,自己琢磨了好久,真是感动TAT #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdli

POJ 1780 Code (欧拉回路+非递归版dfs)

题目地址:POJ 1780 还是求序列的欧拉回路.只不过这题有两坑. 第一坑是用数字来当点的话,会MLE,因为每个数字可以连10条边,100w条边会MLE,即使用vector也会TLE.这题可以用边来记录,对于n为1时直接输出,然后后面的,比如12,23这两个点就用边权值为123来表示这两个点,这样就把点和边的范围都缩小了10倍. 第二坑是用递归的dfs会爆栈,亲测即使加手扩栈也会爆..(简直丧心病狂..)需要用非递归版dfs,也不难,dfs本身就是利用的栈,所以改成栈的形式就可以了. 代码如下

POJ1780 Code

KEY公司开发出一种新的保险箱.要打开保险箱,不需要钥匙,但需要输入一个正确的.由n位数字组成的编码.这种保险箱有几种类型,从给小孩子玩的玩具(2位数字编码)到军用型的保险箱(6位数字编码).当正确地输入最后一位编码后,保险箱就立刻打开了.保险箱上没有“确定”键.当你输入超过n位数字,则只有最后n位数字有效.例如,对一种4位数字编码的型号,如果正确的编码为4567,你想输入的编码为1234567890,则保险箱的门会在你输入数字7后马上就打开了.为了达到这种效果所需要设计的软件其实很简单.对n位

POJ1780 Code(欧拉路径)

n位密码,要用尽可能短的序列将n位密码的10n种状态的子串都包括,那么要尽量地重合. 题目已经说最短的是10n + n - 1,即每一个状态的后n-1位都和序列中后一个状态的前n-1位重合. 这题是经典的欧拉路径问题吧,用n位数字10n种状态来作为边,而用重合的n-1位数字表示点. 具体的建图,每个点都引出10条边(十进制),这10条边就代表着10个n位数,前n-1位的数就代表那个点,然后连向这个边代表数的后n-1位代表的点.. 比如n等于3的时候这么建图(假设密码是二进制,十进制太多了): 这

图论常用算法之一 POJ图论题集【转载】

POJ图论分类[转] 一个很不错的图论分类,非常感谢原版的作者!!!在这里分享给大家,爱好图论的ACMer不寂寞了... (很抱歉没有找到此题集整理的原创作者,感谢知情的朋友给个原创链接) POJ:http://poj.org/ 1062* 昂贵的聘礼 枚举等级限制+dijkstra 1087* A Plug for UNIX 2分匹配 1094 Sorting It All Out floyd 或 拓扑 1112* Team Them Up! 2分图染色+DP 1125 Stockbroker

POJ - 1780 Code (欧拉回路+手写DFS)

Description KEY Inc., the leading company in security hardware, has developed a new kind of safe. To unlock it, you don't need a key but you are required to enter the correct n-digit code on a keypad (as if this were something new!). There are severa

[欧拉回路+手动开栈] poj 1780 Code

题目链接: http://poj.org/problem?id=1780 Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2037   Accepted: 751 Description KEY Inc., the leading company in security hardware, has developed a new kind of safe. To unlock it, you don't need

The Necklace UVA 10054 (无向图的欧拉回路,求证Flury算法)

说说:题目的意思本质上就是给你N条无向边,若存在欧拉回路,则将其生成.无向图的欧拉回路的判断非常容易,只要判断是否每个节点都是偶数度即可.但是,对欧拉回路的生成,也就是Fleury算法,貌似有点问题.我自己在这个地方也纠结了好久.下面就来讲讲Fleury算法. 开始我觉得,就是个非常简单的深度优先搜索的问题,直接从任意一个节点,然后不断DFS即可.所以就有了如下的代码: for(i=1;i<MAX;i++) if(map[m][i]>0){ map[m][i]--; map[i][m]--;

洛谷P1341 无序字母对(欧拉回路)

P1341 无序字母对 题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 输入格式: 第一行输入一个正整数n. 以下n行每行两个字母,表示这两个字母需要相邻. 输出格式: 输出满足要求的字符串. 如果没有满足要求的字符串,请输出“No Solution”. 如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案 输入输出样例 输入样例#1: 4 a