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; }