首页 > 代码库 > poj 1392 构造欧拉路遍历所有可能

poj 1392 构造欧拉路遍历所有可能

http://poj.org/problem?id=1392

其实就是构造一个最小的数字序列,使得每n位都是一个数字,而且不重复 

比如n=2  序列是00110   两个两个看就是00--0  01---1 11--3 10--2

先总结知识:
1、k进制下,这样的序列长度是k^n+n-1.

首先第一个数长度是n,后面k^n -1个数,每个数只需要增加一位就行了,所以是k^n+n-1.

2、最小

我开始的时候按回溯写,WA,然后把vis[ s ]=0注释掉 AC,不是很明白为什么,再做几题作总结


//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;

#define ls(rt) rt*2
#define rs(rt) rt*2+1
#define ll long long
#define ull unsigned long long
#define rep(i,s,e) for(int i=s;i<e;i++)
#define repe(i,s,e) for(int i=s;i<=e;i++)
#define CL(a,b) memset(a,b,sizeof(a))
#define IN(s) freopen(s,"r",stdin)
#define OUT(s) freopen(s,"w",stdout)
const ll ll_INF = ((ull)(-1))>>1;
const double EPS = 1e-8;
const int INF = 100000000;
const int MAXN = 17;
int ans[1<<MAXN],vis[1<<MAXN];

int n,k,all,num;

int dfs(int cnt,int s)
{
    if(cnt == num)return 1;
    for(int i=0;i<=1;i++)
    {
        if(!vis[((s<<1)+i)&all])
        {
            vis[((s<<1)+i)&all]=1;
            int cc=ans[cnt];
            ans[cnt]=i;
            if(dfs(cnt+1, ((s<<1)+i)&all ))return 1;
            //vis[(s<<1)+i]=0;///此处没注释掉的时候,WA。。。
        }
    }
    return 0;
}

void solve()
{
    int out=0;
    for(int i=0;i<k;i++)
    {
        out<<=1;
        out=(out+ans[i+n])&all;
    }
    printf("%d\n",out);
}

int main()
{
   // IN("poj1392.txt");
    while(~scanf("%d%d",&n,&k) && n+k)
    {
        CL(ans,0);
        CL(vis,0);
        num = (1<<n)+n-1;//总的位数
        all = (1<<n)-1;
        k%=(all+1);
        vis[0]=1;
        dfs(n,0);//0~n-1  -- 前n位是0,然后从n+1位开始遍历
        solve();
    }
    return 0;
}


在网上找到了一个非递归版,贴在此膜拜下http://www.cnblogs.com/rolight/p/3863752.html

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

using namespace std;

typedef long long LL;
const int maxn = 1 << 16;
int ans[maxn],n,k,now,lim;
int s[maxn],snow[maxn],top,spos[maxn];
bool hs[maxn];

void dfs1() {
    memset(snow,0,sizeof(snow));
    top = n - 1;
    ans[top] = 0; snow[0] = 0; top++;
    while(top < lim) {
        int w = ans[top - 1];
        if(snow[w] == 2) {
            top--;
            snow[w] = 0;
            hs[w] = false;
            continue;
        }
        for(;snow[w] < 2;snow[w]++) {
            int vv = w & ((1 << (n - 1)) - 1);
            vv = (vv << 1) +  snow[w];
            if(!hs[vv]) {
               ans[top] = vv;
               snow[w]++;
               top++;
               hs[vv] = true;
               break;
            }
        }
    }
}

bool dfs(int now) {
    bool ret = false;
    if(now == lim) return true;
    for(int i = 0;i <= 1;i++) {
        int vv = ans[now - 1] & ((1 << (n - 1)) - 1);
        vv = (vv << 1) + i;
        if(!hs[vv]) {
            hs[vv] = true;
            ans[now] = vv;
            ret |= dfs(now + 1);
        }
        if(ret) break;
    }
    return ret;
}

void solve() {
    for(int i = 0;i < n;i++) ans[i] = 0;
    hs[0] = true;
    /*
    dfs(n);
    */
    dfs1();
    int ret = 0;
    for(int i = 0;i < n;i++) {
        ret = ret << 1;
        ret += ans[(k + i) % (1 << n)] % 2;
    }
    printf("%d\n",ret);
}

int main() {
    while(scanf("%d%d",&n,&k),n) {
        memset(hs,0,sizeof(hs));
        now = 0;
        lim = (1 << n) + n - 1;
        solve();
    }
    return 0;
}


poj 1392 构造欧拉路遍历所有可能