ps:这个文章是 倪老弟所写 哈哈 吉大本校保博的大佬,尊重原创作者! 感谢倪老弟!
我就借用他文章刷刷访问量吧! 希望他有天在csdn上看见自己文章 别打我 ! 开玩笑啦! 大家具体咋做自己看吧。
昨天晚上我看到想了好久怎么做,还去找示例里的规律,大概半小时后,我肯定了,没有数字的规律。接下来的今天,我用了讨论班3个多小时想思路加上晚上3个多小时不停的调试做完了这个题,莫名的开心。
这道题的意思是2的n次方的0、1序列组成的环,环中任意N位的表达的十进制数不同。这个与gray数列完全不同,gray数列通过变换拆分加0、1就可以做到。
首先把示例环表示的十进制数写出来:0、1、2、5、3、7、6、4。接下来的内容中出现的节点都指的是十进制数字串。1是通过0(000)后面放置1得到的,4是通过6(110)后面放置0得到的。所以总结一下:每个数都只有两种后状态,一个是后面放0、一个是后面放1,即,左移一位和左移一位+再加1。也就是说,我把这道题抽象为有向图的时候,每个节点的邻居节点都只有两个。
这样,我们就可以表示所有节点的后状态。如下图所示。第一个是节点,另外两个是指向的邻居节点。(数据结构教材中的表示方法)
我们可以发现,不管N为几,N个0后面一定是1,(因为如果把N个0后面还放置0就马上又出现了一个0),所以这个问就等价于这样一个图,我们要找到一条路径,起始点是1,终点是0,并且这条路径上必须包含所有节点。
大体可以有三种方法:
1.暴力解法
2.用栈的各种操作和标志位,1,0两点之间路径的深搜,选出有全部节点的那条。
3.回溯法,可以用到分支限界,例如有这样一个界限:不能连续N+1个add0或add1还有不能构成N的周期,等等,都可以缩短时间复杂度。
接下来我主要按照第二种思路
每一次的压栈都要伴随着把边的visited赋为1,并且标记已经入栈;每一次的弹栈要取消已经入栈的标记并把弹出的点的边的visited赋值为0(0节点不改visited)。
先压节点1
如果有可以压入的点(不在栈里且边的visited为0),就压进去
没有可以压入的点的话 :当栈顶元素为终点时,弹出栈顶节点
当栈顶不是终点是,弹顶,并改visited
重复,直到栈中元素为空
逻辑基本上是我一点一点试出来的,这些cout也可以更好的理解,怎么弹占压站的逻辑。
代码:
#include <iostream>
#include<stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include<math.h>
#include"queue"
#include"stack"
#define MAX 500
using namespace std;
class Circle
{
public:
int n;
int bit;
int cir[MAX];
int add0[MAX];
int add1[MAX];
int visited0[MAX];
int visited1[MAX];
int stackState[MAX];
int c_position = 0;
public:
int length(char * str)
{
int sum=0;
while(str[sum]!='\0')
{
sum++;
}
return sum;
}
int ten(string x)
{
int i=0;
int sum=0;
for(i=0;i<n;i++)
{
int factor=n-1-i;
int a1=x[i]-48;
sum=sum+ (a1* pow(2,factor));
}
return sum;
}
Circle(int a){
n=a;
bit=pow(2,n);
int i=0;
for(i=0;i<bit;i++)
{
cir[i]=0;
add0[i]=0;
add1[i]=0;
visited0[i]=0;
visited1[i]=0;
stackState[i]=0;
int j=0;
}
//构造N位的二进制数的add0和add1
for(i=0;i<bit;i++)
{
char * bina=new char();
string add0c=new char();
string add1c=new char();
bina=itoa(i,bina,2);
cout<<i<<" : "<<bina<<endl;
if(length(bina)<n)
{
int x1=(i<<1)+1;
int x0=i<<1;
add0[i]=x0;
add1[i]=x1;
}
else
{
add0c=bina;
add1c=bina;
int j=0;
for(j=0;j<n-1;j++)
{
add0c[j]=add0c[j+1];
add1c[j]=add1c[j+1];
}
add0c[n-1]='0';
add1c[n-1]='1';
cout<<i<<" : "<<add0c<<endl;
cout<<i<<" : "<<add1c<<endl;
add0[i]=ten(add0c);
add1[i]=ten(add1c);
}
delete bina;
}
}
void outputALL()
{
int i=0;
for(i=0;i<bit;i++)
{
cout<<i<<" "<<stackState[i]<<" "<<add0[i]<<" "<<visited0[i]<<" "<<add1[i]<<" "<<visited1[i]<<" "<<endl;
}
}
void allTrack()
{
int start=1;
int endNode=0;
stack <int> s;
int c_position = 0;
s.push(start);
stackState[start]=1;
int top;
int tmp;
top=start;
int flag=0;
//实现类似深搜的过程
while((!s.empty())&&(flag==0))
{
if(stackState[add0[top]]==0&&visited0[top]==0)
{
s.push(add0[top]);
visited0[top]=1;
stackState[add0[top]]=1;
cout<<"push: "<<add0[top]<<endl;
outputALL();
top=s.top();
}
else if(stackState[add1[top]]==0&&visited1[top]==0)
{
s.push(add1[top]);
visited1[top]=1;
stackState[add1[top]]=1;
cout<<"push: "<<add1[top]<<endl;
outputALL();
top=s.top();
}
else
{
if( top==endNode && s.size()==bit ) flag=1;
else if(top==endNode)
{
stackState[top]=0;
s.pop();
top=s.top();
outputALL();
}
else
{
top=s.top();
s.pop();
stackState[top]=0;
visited0[top]=0;
visited1[top]=0;
top=s.top();
outputALL();
}
}
}
cout<<flag<<endl;
int i=0;
for(i=bit-1;i>=0;i--)
{
cir[i]=s.top();
s.pop();
}
}
void result()
{
char * bina=new char();
int i=0;
for(i=0;i<bit;i++)
{
cout<<cir[i]<<" ";
}
cout<<endl;
for(i=0;i<bit;i++)
{
bina=itoa(cir[i],bina,2);
if(length(bina)==n) cout<<1;
else cout<<0;
}
cout<<endl;
}
};
int main()
{
int i=0;
int n;
cin>>n;
Circle c(n);
c.allTrack();
c.result();
return 0;
}
改进意见:有更好构造图的方法会可能更好,或者不把这个题抽象为图。
N=10 :
用N=3的加上中间的cout好理解一些
欢迎加入吉林大学计算机软件考研群::710212002