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

和西安邀请赛那道题题目差不多,现在终于会手写栈了,自己琢磨了好久,真是感动TAT

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <string>
#include <iostream>
#include <map>
#include <cstdlib>
#include <set>
#include <queue>
#include <stack>

using namespace std;

typedef long long LL;
const int maxn = 1e6 + 100;
int n,ans[maxn],lim,p10[10],vnow[maxn];
int s[maxn],top,spos[maxn];
bool hs[maxn];

void dfs1() {
    memset(vnow,0,sizeof(vnow));
    top = 0;
    for(int i = 0;i < lim;i++) ans[i] = 0;
    hs[0] = true;
    vnow[0] = 1;
    s[top] = 0;
    spos[top] = n;
    top++;
    while(top > 0) {
        int w = s[top - 1],pos = spos[top - 1];
        if(pos == lim) break;
        if(vnow[w] == 10) {
            hs[w] = false;
            vnow[w] = 0;
            top--;
        }
        for(;vnow[w] < 10;vnow[w]++) {
            int vv = w * 10 % p10[n] + vnow[w];
            if(!hs[vv]) {
                hs[vv] = true;
                s[top] = vv; spos[top] = pos + 1; top++;
                vnow[w]++;
                ans[pos] = vv;
                break;
            }
        }
    }
}

bool dfs(int now) {
    bool ret = false;
    if(now == lim) return true;
    for(int i = 0;i < 10;i++) {
        int val = 0;
        if(now >= n - 1) val = ans[now - 1] * 10 % p10[n] + i;
        if(now >= n) {
            if(!hs[val]) {
                hs[val] = true;
                ans[now] = val;
                ret |= dfs(now + 1);
                hs[val] = false;
            }
        }
        else if(now == n - 1) {
            hs[val] = true;
            ans[now] = val;
            ret |= dfs(now + 1);
            hs[val] = false;
        }
        else {
            ans[now] = i;
            ret |= dfs(now + 1);
        }
        if(ret) break;
    }
    return ret;
}

void solve() {
    memset(hs,0,sizeof(hs));
    lim = p10[n] + n - 1;
    dfs1();
    for(int i = 0;i < lim;i++) printf("%d",ans[i] % 10);
    puts("");
    /*
    memset(hs,0,sizeof(hs));
    dfs(0);
    for(int i = 0;i < lim;i++) printf("%d",ans[i] % 10);
    puts("");
    */
}

int main() {
    p10[0] = 1;
    for(int i = 1;i < 10;i++) p10[i] = p10[i - 1] * 10;
    while(scanf("%d",&n),n) solve();
    return 0;
}

  

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

时间: 2024-10-30 09:49:32

POJ 1780 Code 欧拉回路+手写栈DFS的相关文章

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

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

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

dfs手写栈模板

在竞赛中如果系统栈很小的话,过深的递归会让栈溢出,这个时候我们就要自己手写栈,将递归转化成手工栈. 方法其实也很简单. 基本思路上,我们就是用栈不断的pop,push.但是何时push,何时pop呢? 在<算法导论>上对深度优先遍历树的讲解中,在深度遍历中,会对每个节点进行染色,白色为没有被访问过:灰色为被访问过,但是该节点的所有子树还没有完成访问:黑色,节点被访问过,而且该节点的所有子树都被完全的访问. 所以,我们就通过颜色标记来进行判断了. 整体的框架如下: memset(vis,0,si

POJ 1780 Code

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

手写栈(递归转化为非递归)

递归的本质是通过栈来保存状态,然后再次调用自己进入新的状态,然后函数返回的时候回到上次保存的状态. 如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的.当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归.尾递归函数的特点是在回归过程中不用做任何操作,就是没有回溯过程,所以我们可以直接将尾递归写成循环 更一般的递归,想要转化为非递归,就需要模拟栈(手写栈)的行为. 遍历的递归和非递归实现: #include<cstdio>

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

/* 对于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 要求字典序最小 这里建边时

手写栈,队列

1 struct sta 2 { 3 int sz[100001]; 4 int top() 5 { 6 return sz[top]; 7 } 8 void push(int x){ 9 sz[++top]=x; 10 } 11 void pop(){ 12 if(top>0) 13 top--; 14 } 15 void cl() 16 { 17 top=0; 18 } 19 int size(){ 20 return top; 21 } 22 }stack; 23 24 stack 1 #

POJ 1780 Code(欧拉通路)

输入n(1<=n<=6),输出长度为10^n + n -1 的字符串答案. 其中,字符串以每n个为一组,使得所有组都互不相同,且输出的字符串要求字典序最小. 显然a[01...(n-1)]和a[12...n]为相邻组,可以看做有一条边从结点a[01...(n-1)]到结点a[12...n]. 题目转化成求欧拉通路.如果以每组的值为结点,则有10^6个结点,10^7条边.会MLE.(此时其实是哈密顿通路?) 这里以每组的值为边的边权,而边的2个结点分别是前n-1位数和后n-1位数.这样点是10^