POJ 1780 【手工递归】【欧拉回路】

题意:

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

POJ 1780 【手工递归】【欧拉回路】的相关文章

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 (欧拉回路+非递归版dfs)

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

poj 1780 , poj 1392 欧拉回路求前后相互衔接的数字串

两道题目意思差不多 第一题是10进制 , 第二题是2进制的 都是利用欧拉回路的fleury算法来解决 因为我总是希望小的排在前面,所以我总是先将较小数加入栈,再利用另一个数组接收答案,但是这里再从栈中导出来答案要倒一下了,这一点要注意 poj 1780 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 using namespace std; 5 #define N 1000010 6 7 int

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

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

poj 2533 poj 2533 普通递归超时1 2

#include <iostream>#define N 10005using namespace std;int a[N],n,maxlen=1;int f( int x){ int i,t,m; if (x<=0) return 1; m=1; for (i=0;i<x; i++) { t=f(i);        if (a[x]>a[i])        {   m=max(m,t+1);              if (m>maxlen) maxlen=m;

POJ 1780 Code

记录欧拉路径. 题意很难懂.英语渣,翻译半天不得要领.看PDF的中文才知道题意. 题意:给一个 N (1<=N<=6)找出字典序最短的所有数字组合都出现的序列. 给出了N=2 的例子.就拿这个说明,太长就说前面的. 00102030405060708091121314151617181922324252627282933435363738394454647484955657585966768697787988990 00 出现了,01出现,然后 10,02,20,03,30,04,40,05,

[欧拉回路+手动开栈] 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

poj 1780 欧拉回路构造字符串

和西安邀请赛D题类似的题目 这道题会爆栈,所以要非递归写,但是看了很久其实代码没理解,回头重写 题解:http://blog.csdn.net/dongshimou/article/details/37815377 http://www.cnblogs.com/372465774y/p/3200775.html #include <cstdio> #include <cmath> #include <iostream> using namespace std; cons

poj 1300 Door Man 欧拉回路

题目链接:http://poj.org/problem?id=1300 You are a butler in a large mansion. This mansion has so many rooms that they are merely referred to by number (room 0, 1, 2, 3, etc...). Your master is a particularly absent-minded lout and continually leaves door