(以下答案均由本人自己编写,欢迎大家一起交流)
建议在完成本次实验前对DFS算法有一定了解。
题目编号:Exp08-Enhance02,GJBook3-12-17
题目名称:Debruijn问题
题目描述:
如图所示由2^3 个二进制数字0和1组成一个环。使 2^3 个 3 位的二进制数正好在环中各出现一次。图中目前所示顺序是:0、1、2、5、3、7、6、4。设计生成这样环的程序,环由 2^n 个二进制数字组成,恰好包含 2^n 个互不相同的n位二进制数。
输入:n(n<=4)
输出:按照字典序输出符合的答案(当出现多组本质不同的解时,仅输出字典序中最小的那个序列);每行数字间以一个西文空格间隔,行末有一个换行符。
样例1:
输入:
3
输出:
0 0 0 1 0 1 1 1
思路:
这里我们仍采用dfs算法。
我的思路是先生成所有的n位二进制数,以n=3举例有000,001,010,011,100,101,110,111.我们从头开始排这些二进制数,显然,由于输出的是字典序中最小的那个序列,所以开头我们可以先填入000,然后在剩下的数中寻找前两项是00的二进制数,如001,那我们将1填入序列。再寻找开头为01的二进制数,如010,011,
以上是递归思路
以下是递归出口的设置
仍以n=3举例,当我们填入了7个数时,我们已经把二进制数填完了(000开头就已被填入,所以只需填剩下的七个数)但这时候序列中有十个数,因为要构成环,所以结尾的两个数要与开头的两个数相同,如若相同,则满足提议,我们就找出了一个Debruijn序列。
代码:
#include<stdio.h>
int a[20][5],n,b[5],p=0,d[200],book[20]={0}/*用来标记数是否被使用过*/,e[200][200],p1=0;
int cmp(int t,int w);//判断该数的前n-1项是否与序列的后n-1项相同
void dfs(int w){
int j,i;
if(w==p){//递归出口
for(j=0;j<n;j++){
if(d[j]!=d[j+p])return;
}
for(j=0;j<p;j++){
e[p1][j]=d[j];//将满足条件的序列填入e中
}
p1++;
return;
}
for(i=0;i<p;i++){
if(book[i]==0&&cmp(i,w)){
d[w+n-1]=a[i][n-1];
book[i]=1;//标记该数已使用
dfs(w+1);//走一步
book[i]=0;//这是最重要的一步!一定要将尝试的数收回,才能尝试下一步
}
}
}
int cmp(int t,int w){
int i;
for(i=0;i<n-1;i++){
if(a[t][i]!=d[w+i])return 0;
}
return 1;
}
void put(void){
int i;
for(i=0;i<n;i++){
a[p][i]=b[i];//将生成的二进制数填入a中
}
p++;
}
void exh(int m){//生成二进制数
int i;
if(m==n){
put();
}
else if(m<n){
for(i=0;i<=1;i++){
b[m]=i;
exh(m+1);
}
}
}
int main(void){
int i;
scanf("%d",&n);
for(i=0;i<n;i++){
d[i]=0;
}
book[0]=1;
exh(0);
dfs(1);
for(int j=0;j<p;j++){
printf("%d",e[0][j]);//e中的第一个序列就是字典序最小的序列
if(j!=p-1){
printf(" ");
}
else printf("\n");
}
}
欢迎大家在评论区交流