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;
    }
  • 相关阅读:
    CS229 6.4 Neurons Networks Autoencoders and Sparsity
    CS229 6.3 Neurons Networks Gradient Checking
    【Leetcode】【Easy】Min Stack
    【Leetcode】【Easy】Merge Sorted Array
    【Leetcode】【Easy】ZigZag Conversion
    【Leetcode】【Easy】Valid Palindrome
    【Leetcode】【Easy】Reverse Integer
    【Leetcode】【Easy】Palindrome Number
    【Leetcode】【Easy】Length of Last Word
    【Leetcode】【Easy】Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/Lyush/p/3038508.html
Copyright © 2011-2022 走看看