• hihoCoder #1182 欧拉路·三 (变形)


    题意:

      写出一个环,环上有2^n个格子,每个格子中的数字是0或1,相连着的n个格子可以组成一个数的二进制,要求给出这2^n个数字的序列,使得组成的2^n个数字全是不同的。(即从0到2^n-1)

    思路:

      构造一个图,但是只需要考虑边,每条边假设为n个0/1组成的串,即此图有2^n条边,每边代表1个数字。若两边经过同一个点,则可以从一条边k经过 (k<<1)+0/1就是左边去掉1位,再左移一位,再在后面添加0或1,就相当于切换到另外一边。既然可以在后面添加0或1,那么就相当于一个点有两条出边,那么也就可以看到每个点也有两条入边。边1001和0001都可以转成0011和0010。此时他们经过了1个点,前两条边为入边,后两条边为出边(如图)。

            

      可以从0开始出发,进行暴力DFS,需要注意的只是路径应该是欧拉路的路径,要从回溯开始计起,为了防止无限循环,要记录下访问过的路径。但是所要的答案是顺时针的,所以要从路径的前面开始输出。每次输出二进制的最后一位即可。 注:这是有向图,但是每个点都是入度=出度=2,那么可以从任意一个点出发,不仅限于0出发。(因为没有入度!=出度的点,该点是起/终点)

     1 #include <bits/stdc++.h>
     2 #define N 16
     3 using namespace std;
     4 int num[N], n, mod=1, vis[50000],ans[50000],q;//上限3万多条边
     5 void fleury(const int &t)
     6 {
     7     vis[t]=true; //该边访问过
     8     int tmp=((t&mod)<<1);     //去掉最高位再左移一位
     9     if(!vis[tmp])    fleury(tmp);          
    10     if(!vis[++tmp])    fleury(tmp);
    11     ans[q++]=t;//路径:记录走过的边
    12 }
    13 int main()
    14 {
    15     //freopen("input.txt", "r", stdin);
    16     scanf("%d",&n);
    17     for(int i=2; i<n; i++)  mod=(mod<<1)+1;  //去掉最高位时有用到
    18     fleury(0);
    19     for(int i=q-1; i>=0; i--)    printf("%d",ans[i]&1);//任一合法答案
    20     return 0;
    21 }
    AC代码
  • 相关阅读:
    【转载】天才与柱子
    Windows Phone 7 隔离存储空间资源管理器
    (收藏)让你平步青云的十个谈话技巧
    (收藏)《博客园精华集》设计模式分册
    (收藏)C#开源资源大汇总
    (收藏)生活物语
    (收藏)C# ORM/持久层框架
    (收藏)《博客园精华集》AJAX与ASP.NET AJAX部分
    小型项目总结之五
    VS 打包完美解决方案
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4595894.html
Copyright © 2020-2023  润新知