UOJ#117. 欧拉回路【栈维护欧拉回路】

题目链接


  记住的是这道题是欧拉回路,而不是欧拉通路,两者是有本质上的差别的。

  欧拉回路与欧拉通路相同,主要原理还是在于一个栈的巧上面,这个栈真的用的很巧,也就是相当于,我们虽然有其他的路径可以走,而且我们尽管现在是随机跑的,可能会忽略一些边,使得欧拉回路不完整,但是呢,我们用栈就可以很好的避免了这个问题了哟。

  我们现在虽然是往下走了(而且强调一个随机性),但是呢,我们之后回溯回来再走的时候,其实还是会把原来的路径打开一个缺口,把现在的这条链放进去就是了。

  stack在欧拉通路和欧拉回路中真好用!!!

我的code中,打注释掉的部分是欧拉通路,另外的是欧拉回路部分。看需求了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
//#include <unordered_map>
//#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int op, N, M, head[maxN], cnt;
struct Eddge
{
    int nex, to, id;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), id(c) {}
}edge[maxN << 2];
inline void addEddge(int u, int v, int id)
{
    edge[cnt] = Eddge(head[u], v, id);
    head[u] = cnt++;
}
inline void _add(int u, int v, int id) { addEddge(u, v, id); addEddge(v, u, -id); }
stack<int> st, ans;
int In_du[maxN] = {0}, Out_du[maxN] = {0}, du[maxN] = {0}, root[maxN];
inline int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
bool vis_line[maxN << 2] = {false}, vis[maxN] = {false};
stack<int> pre[maxN];
inline void un_dir()
{
    for(int i=1, u, v, fu, fv; i<=M; i++)
    {
        scanf("%d%d", &u, &v);
        vis[u] = vis[v] = true;
        _add(u, v, i);
        du[u]++; du[v]++;
        fu = fid(u); fv = fid(v);
        if(fu ^ fv) root[fu] = fv;
    }
    int num_root = 0;
    for(int i=1; i<=N; i++) num_root += (vis[i] && i == fid(i));
    if(num_root > 1) { printf("NO\n"); return; }
    int S = 0, tri_num = 0;
    for(int i=1; i<=N; i++)
    {
        if(du[i] & 1)
        {
//            S = i;
//            tri_num ++;
            printf("NO\n"); return;
        }
    }
//    if(tri_num > 2) { printf("NO\n"); return; }
    if(!S)
    {
        S = 1;
        while(!vis[S] && S <= N) S++;
        if(S > N) { printf("YES\n"); return; }
    }
    st.push(S);
    int u, v;
    while(!st.empty())
    {
        u = st.top();
        if(~head[u])
        {
            while(~head[u] && vis_line[head[u]])
            {
                head[u] = edge[head[u]].nex;
            }
            if(head[u] == -1) continue;
            v = edge[head[u]].to;
            pre[v].push(edge[head[u]].id);
            vis_line[head[u]] = vis_line[head[u] ^ 1] = true;
            head[u] = edge[head[u]].nex;
            st.push(v);
        }
        else
        {
            if(!pre[u].empty())
            {
                ans.push(pre[u].top());
                pre[u].pop();
            }
            st.pop();
        }
    }
    printf("YES\n");
    while(!ans.empty())
    {
        printf("%d", ans.top());
        ans.pop();
        if(!ans.empty()) printf(" ");
        else printf("\n");
    }
}
inline void dir()
{
    for(int i=1, u, v, fu, fv; i<=M; i++)
    {
        scanf("%d%d", &u, &v);
        vis[u] = vis[v] = true;
        addEddge(u, v, i);
        In_du[v]++; Out_du[u]++;
        fu  =fid(u); fv = fid(v);
        if(fu ^ fv) root[fu] = fv;
    }
    int num_root = 0;
    for(int i=1; i<=N; i++) num_root += (vis[i] && i == fid(i));
    if(num_root > 1) { printf("NO\n"); return; }
    int S = 0, E = 0;
    for(int i=1; i<=N; i++)
    {
        if(Out_du[i] == In_du[i]) continue;
        printf("NO\n");
        return;
//        if(Out_du[i] == In_du[i] + 1)
//        {
//            if(S) { printf("NO\n"); return; }
//            S = i;
//        }
//        else if(Out_du[i] == In_du[i] - 1)
//        {
//            if(E) { printf("NO\n"); return; }
//            E = i;
//        }
    }
    if(!S)
    {
        S = 1;
        while(!vis[S] && S <= N) S++;
        if(S > N) { printf("YES\n"); return; }
    }
    int u, v;
    st.push(S);
    while(!st.empty())
    {
        u = st.top();
        if(~head[u])
        {
            v = edge[head[u]].to;
            pre[v].push(edge[head[u]].id);
            head[u] = edge[head[u]].nex;
            st.push(v);
        }
        else
        {
            if(!pre[u].empty())
            {
                ans.push(pre[u].top());
                pre[u].pop();
            }
            st.pop();
        }
    }
    printf("YES\n");
    while(!ans.empty())
    {
        printf("%d", ans.top());
        ans.pop();
        if(!ans.empty()) printf(" ");
        else printf("\n");
    }
}
inline void init()
{
    cnt = 0;
    for(int i=1; i<=N; i++)
    {
        head[i] = -1;
        root[i] = i;
    }
}
int main()
{
    scanf("%d%d%d", &op, &N, &M);
    init();
    if(op == 1) un_dir();
    else dir();
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值