HihoCoder 1182-欧拉路·三(有向图打印路径)

#1182 : 欧拉路·三

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

小Hi和小Ho破解了一道又一道难题,终于来到了最后一关。只要打开眼前的宝箱就可以通关这个游戏了。

宝箱被一种奇怪的机关锁住:

这个机关是一个圆环,一共有2^N个区域,每个区域都可以改变颜色,在黑白两种颜色之间切换。

小Ho控制主角在周围探索了一下,果然又发现了一个纸片:

机关黑色的部分表示为1,白色的部分表示为0,逆时针连续N个区域表示一个二进制数。打开机关的条件是合理调整圆环黑白两种颜色的分布,使得机关能够表示0~2^N-1所有的数字。
我尝试了很多次,终究没有办法打开,只得在此写下机关破解之法。
	——By 无名的冒险者
	

小Ho:这什么意思啊?

小Hi:我给你举个例子,假如N=3,我们通过顺时针转动,可以使得正下方的3个区域表示为:

因为黑色表示为1,白色表示为0。则上面三个状态分别对应了二进制(001),(010),(101)

每转动一个区域,可以得到一个新的数字。一共可以转动2^N次,也就是2^N个数字。我们要调整黑白区域的位置,使得这2^N个数字恰好是0~2^N-1

小Ho:我懂了。若N=2,则将环上的黑白色块调整为"黑黑白白",对应了"1100"。依次是"11","10","00","01"四个数字,正好是0~3。那么这个"黑黑白白"就可以打开机关了咯?

小Hi:我想应该是的。

小Ho:好像不是很难的样子,我来试试!

提示:有向图欧拉回路

输入

第1行:1个正整数,N。1≤N≤15

输出

第1行:1个长度为2^N的01串,表示一种符合要求的分布方案

样例输入
3
样例输出
00010111

解题思路:其实题目中已经给你解题的思路了,接下来主要是自己把图建好,然后,求出这个图的欧拉回路,并打印出路径。

建图方式:对于一个数把它化成二进制表示(表示的位数与最大的那个数(2^n-1)一致),然后删除二进制表示的最低位得数num1, 删除最高位(注意不一定是1,例如00110->0110)得数num2,然后num1到num2有一条有向边,然后注意有向图打印路径时要倒着打。

AC代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#define bug printf("*********\n");
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define in1(a) scanf("%d" ,&a);
#define in2(a, b) scanf("%d%d", &a, &b);
#define out1(a) printf("%d\n", a);
#define out2(a, b) printf("%d %d\n", a, b);
using namespace std;
typedef long long LL;
typedef pair<int, int> par;
const int mod = 1e9+7;
const int INF = 1e9+7;
const int N = 1000010;
const double pi = 3.1415926;

int n, cnt, sum;
int head[100010], vis[1000110], path[100010];

struct node
{
    int to;
    int next;
}e[100010];

void add(int u, int v)
{
    e[cnt].to = v;
    e[cnt].next  = head[u];
    head[u] = cnt ++;
}

void dfs(int k)
{
    for(int i = head[k]; i != -1; i = e[i].next) {
        int en = e[i].to;
        if(vis[i]) continue;
        vis[i] = 1;
        dfs(en);
    }
    path[sum ++] = k;
}

int main()
{
    while(~scanf("%d", &n)) {
        cnt = 0;
        sum = 0;
        mem1(head);
        mem0(vis);
        for(int i = 0; i <= pow(2,n) - 1; i ++) {
            int s = (1<<(n-1))-1;
            if(n == 1) s = 1;
            add(i>>1, i&s);
        }
        dfs(0);
        //有同学可能有疑惑为什么是sum-2而不是sum-1
        //因为我们在求路径的时候又回到了起点啊,所以要把它去掉
        for(int i = sum-2; i >= 0; i --) {
            printf("%d", path[i]&1);
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/i_believe_cwj/article/details/80463258