zoukankan      html  css  js  c++  java
  • POJ1392 Ouroboros Snake 欧拉回路

    题意:对于一个长度为2^N的循环序列,从某一个位置开始依次取N个,这样就能够生成2^N个序列,现在要求输出一个最小的满足要求的循环序列。输出这个序列生成的第K个数字是多少?

    解法:套用Fleury算法,构边的时候保持从小到大的顺序即可。如果是生成N为序列的话,就考虑前N-1位构成的节点相互的连的边(例如三位数就可以这样构边 00 --> 01 --> 11那么这两条边就代表生成了001和011这两个数字),输出欧拉回路即可。

    代码如下:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = (1 << 15);
    int n, k;
    int stk[MAXN+5];
    int path[MAXN+5];
    int ans[MAXN+5];
    int top;
    
    struct Node { // f用来标志边是否被删除 
        int v, f;
        int next;
    }e[MAXN*2+5]; // 每个节点最多生成两条边
    
    int head[MAXN+5], idx; 
    
    void insert(int a, int b) {
    //    printf("a = %d, b = %d\n", a, b);
        e[idx].v = b, e[idx].f = 1;
        e[idx].next = head[a];
        head[a] = idx++;
    }
    
    void dfs(int x) {
        for (int i = head[x]; i != -1; i = e[i].next) {
            if (e[i].f) {
                stk[top++] = e[i].v;
                e[i].f = 0;
                dfs(e[i].v);
                break;
            }
        }    
    }
    
    void fleury(int ss) {
        int cnt = 0;
        top = 0;
        stk[top++] = ss;
        while (top > 0) {
            int brige = 1, v = stk[top-1];
            for (int i = head[v]; i != -1; i = e[i].next) {
                if (e[i].f) {
                    brige = 0;
                    break;
                }
            }
            if (!brige) {
                dfs(v);
            } else {
                --top; // 某联通子集中节点出栈
                path[cnt++] = v;
            }
        }
        for (int i = cnt-2, j = 0; i >= 0; --i, ++j) {
            ans[j] = (path[i+1] << 1) | (path[i] & 1);
        //    printf("path[%d] = %d\n", j, ans[j]);
        }
    }
    
    int main() {
        while (scanf("%d %d", &n, &k), n|k) {
            idx = 0; 
            memset(head, 0xff, sizeof (head));
            int lim = 1 << (n-1); // 只将前n-1位作为节点,后面一位放到边上,那么每条边都遍历一遍即使最后的结果 
        //    printf("lim = %d\n", lim);
            for (int i = 0; i < lim; ++i) {
                // 从每个节点有两个节点出去
                int t = i & ((lim-1)>>1);
                insert(i, t<<1|1);
                insert(i, t<<1); // 由于采用的前插入,因此较小的边后插入 
            }
            fleury(0);
            printf("%d\n", ans[k]);
        }
        return 0;
    }
  • 相关阅读:
    Python 读取二进制、HTML 、XML 格式存储的 Excel 文件
    ios自动将长数字(7位)转成电话号码
    前端常见手撕源码
    在微信里及QQ浏览器里ios短信回填vue方法取不到值,去除黄色背景
    js添加css到head中
    WEB 基础认证(BasicAuth)
    Word如何插入PDF格式矢量图片
    【解决】MATLAB中报错:无法将双精度值 0.0401495 转换为句柄
    【解决】Word中插入图片后变模糊
    使用SuperSocket开发联网斗地主(三):抢地主
  • 原文地址:https://www.cnblogs.com/Lyush/p/3038508.html
Copyright © 2011-2022 走看看