洛谷 P7771:【模板】欧拉路径

【题目来源】
https://www.luogu.com.cn/problem/P7771

【题目描述】
求有向图字典序最小的欧拉路径。

【输入格式】
第一行两个整数 n,m 表示有向图的点数和边数。
接下来 m 行每行两个整数 u,v 表示存在一条 u→v 的有向边。

【输出格式】
如果不存在欧拉路径,输出一行 No。
否则输出一行 m+1 个数字,表示字典序最小的欧拉路径。

【输入样例】
4 6
1 3
2 1
4 2
3 3
1 2
3 4

【输出样例】
1 2 1 3 3 4 2

【说明/提示】
对于 50% 的数据,n,m≤10^3。
对于 100% 的数据,1≤u,v≤n≤10^5,m≤2×10^5。
保证将有向边视为无向边后图连通。

【算法分析】
● 欧拉路径与欧拉回路定义
图中经过所有边恰好一次的路径称为
欧拉路径(也就是一笔画)。
如果此路径的起点和终点相同,则称其为
欧拉回路
注意:若存在欧拉回路,则一定存在欧拉路径。

● 欧拉路径判定
(1)
有向图欧拉路径:图中恰好存在 1 个结点的出度比入度多 1(这个结点即为起点 S),1 个结点的入度比出度多 1(这个结点即为终点 T),其余结点的出度=入度。
(2)
有向图欧拉回路:所有结点的入度=出度(起点 S 和终点 T 可以为任意点)。
(3)
无向图欧拉路径:图中恰好存在 2 个结点的度是奇数,其余结点的度为偶数,这两个度为奇数的结点即为欧拉路径的起点 S 和终点 T。
(4)
无向图欧拉回路:所有结点的度都是偶数(起点 S 和终点 T 可以为任意结点)。

● 欧拉路径与欧拉序的区别
欧拉序:
https://blog.csdn.net/hnjzsyjyj/article/details/139674161

【算法代码】

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;
vector<int> g[maxn];
int ind[maxn];
int ne[maxn];
stack<int> ans;

void dfs(int u) {
    int i=ne[u];
    while(i<g[u].size()) {
        ne[u]=i+1;
        dfs(g[u][i]);
        i=ne[u];
    }
    ans.push(u);
}

int main() {
    int n,m;
    cin>>n>>m;
    for(int i=1; i<=m; i++) {
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        ind[y]++;
    }

    int sp=1; //starting point
    int out=0,in=0;
    for(int i=1; i<=n; i++) {
        sort(g[i].begin(),g[i].end());
        int cnt=g[i].size();
        if(ind[i]==cnt-1) out++,sp=i;
        else if(ind[i]==cnt+1) in++;
        else if(cnt!=ind[i]) {
            cout<<"No"<<endl;
            return 0;
        }

        if(in>1 || out>1) {
            cout<<"No"<<endl;
            return 0;
        }
    }

    dfs(sp);
    while(ans.size()) {
        cout<<ans.top()<<" ";
        ans.pop();
    }

    return 0;
}

/*
in:
4 6
1 3
2 1
4 2
3 3
1 2
3 4

out:
1 2 1 3 3 4 2
*/



【参考文献】
https://www.luogu.com.cn/problem/solution/P7771
https://blog.csdn.net/hnjzsyjyj/article/details/139674161
https://www.cnblogs.com/pure4knowledge/p/18115374
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值