UESTC 1642 老当益壮, 宁移白首之心? 欧拉回路、Fleury算法

129 篇文章 0 订阅
117 篇文章 2 订阅

老当益壮, 宁移白首之心?

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)


Submit  Status
请构造一个01串,使其满足以下条件:


环状(即首尾相连)
每一位取值为0或1
长度是2^n
对于每个(2^n个)位置,从其开始沿逆时针方向的连续的n位01串(包括自己)构成的数均不相同,即0到(2^n)−1中的数各出现一次


Input

输入一个整数n(1≤n≤15)


Output

输出任一一个长度为2n且满足题意的01串(顺逆时针均可),保证输入有解。


Sample input and output

Sample Input Sample Output

3                             00010111


Hint

样例的00010111,对于每个位置,沿逆时针方向连续长度为3的01串有:000,001,010,101,011,111,110,100即为0−7的所有数字


Source

2017 UESTC Training for Graph Theory

UESTC 1642 老当益壮, 宁移白首之心?


My Solution

题意:构造一个01串,使其满足以下条件:
环状(即首尾相连)
每一位取值为0或1
长度是2^n
对于每个(2^n个)位置,从其开始沿逆时针方向的连续的n位01串(包括自己)构成的数均不相同,
即0到(2^n) - 1中的数各出现一次


欧拉回路、Fleury算法
考虑用一条边表示一个数,那么题目要求就是无重复的遍历完所有边,
则这是一个欧拉图的问题。
对于有公共点的两条边,第一个的后n-1位和第二个的前n-1相同。
这样将一条边的前n-1位和后n-1位作为点,连边,这样来表示它。
如:对于01101,我们可以从0110向1101建一条有向边表示01101.
于是所建图有2^(n-1)个点,和2^n条边。
对于任一两个点,如果它们的前n-2位和后n-2位相同,就连一条有向边,
这样所得到的图一定是欧拉图,
因为每个点的入度和出度都是2,一定存在欧拉回路。
时间复杂度 O(V + E)
空间复杂度 O(V + E)


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
typedef long long LL;
typedef pair<int, int> ii;
const int MAXN = (1<<14) + 8;
const int MAXM = (1<<15) + 8;

vector<ii> adj[MAXN];
bool vis[MAXM];

inline void add(int x, int y, int z){ //z is the edge who disjoint x and y.
    adj[x].push_back(ii(z, y));
}
vector<int> path;
inline void dfs(int u){
    int v, e;
    while(!adj[u].empty()){
        v = adj[u].back().second, e = adj[u].back().first;
        adj[u].pop_back();
        if(!vis[e]){
            vis[e] = true;
            dfs(v);
            path.push_back(e);
        }
    }
}
inline bool get_path(){
    int i, j, sz;
    int origin = 0;
    path.clear();
    memset(vis, false, sizeof vis);
    dfs(origin);
    return true;
}

int main()
{
    #ifdef LOCAL
    freopen("i.txt", "r", stdin);
    //freopen("i.out", "w", stdout);
    int T = 1;
    while(T--){
    #endif // LOCAL
    //ios::sync_with_stdio(false); cin.tie(0);

    int n, u, v, i;
    //cin >> n;
    scanf("%d", &n);
    for(i = 0; i < (1<<n); i++){
        u = i >> 1;
        v = i % (1<<n-1);
        add(u, v, i);
    }
    get_path();
    int sz = 1<<n;
    for(i = 0; i < sz; i++){
        putchar(char('0' + (path[i] & 1)));
    }
    putchar('\n');

    #ifdef LOCAL
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}



  Thank you!

                                                                                                                                             ------from ProLights

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值