吉林大学 2017年 966 第六题

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好理解一些
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zqx951102/article/details/84990585