欧拉路径杂题

欧拉路径杂题

欧拉路径:通过图中所有边恰好一次而且走遍了所有点(允许多次经过同一个点) 的通路是欧拉路径

如果这条路径的起点和终点重合 那么就是欧拉回路

注意 显然欧拉回路一定是欧拉路径的子集 下面讲一下分别判断的方式(即假定欧拉路径并不包含欧拉回路 这两个东西的判断是分开的)

判定:

  • 有向图欧拉路径:图中恰好存在一个点cd[u]=rd[u]+1(作起点 一个点rd[u]=cd[u]+1(作终点) 其余所有节点rd[u]=cd[u]
  • 有向图欧拉回路:图中所有点的rd[u]=cd[u]
  • 无向图欧拉路径:图中恰好存在两个点的度数是奇数 其他为偶数
  • 无向图欧拉回路:所有的点的度数都是偶数

P7771 【模板】欧拉路径

将每一个节点的出边排序 保证字典序最小 并加一个now[u]表示这个u点的出边用到哪一条了 可以优化复杂度

同时 我们根据上面的1,2条规则 记录cnt[0]表示cd[u]=rd[u]+1的点的个数 cnt[1]反之

那么只有cnt[0]=cnt[1]=0/1的情况才是合法的

最后用dfs搜一遍并用栈输出即可 搜的时候相当于从起点开始 每次走完一条边就删一条边 最终可以保证每一个点的出入度都是0

总复杂度O(n+mlogm) 瓶颈在排序 但足以通过本题

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define pii pair<int,int>
#define eb emplace_back
#define mkp make_pair
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int n , m , now[N] , rd[N] , cd[N] , sta[N] , top , cnt[2] , s = 1;

vector<int> e[N];
void add ( int u , int v ) { e[u].emplace_back(v); }

void dfs ( int u )
{
	while ( now[u] < e[u].size() ) now[u] ++ , dfs(e[u][now[u]-1]);
	sta[++top] = u;	
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read() , m = read();
	for ( int i = 1 , u , v ; i <= m ; i ++ ) u = read() , v = read() , add ( u , v ) , rd[v] ++ , cd[u] ++;
	for ( int i = 1 ; i <= n ; i ++ ) sort ( e[i].begin() , e[i].end() );
	for ( int i = 1 ; i <= n ; i ++ )
	{
		if ( abs ( cd[i] - rd[i] ) > 1 ) return cout << "No" << endl , 0;
		if ( cd[i] - rd[i] == 1 ) cnt[0] ++ , s = i;
		else if ( rd[i] - cd[i] == 1 ) cnt[1] ++;
	}
	if ( ! ( ( cnt[0] == 1 && cnt[1] == 1 ) || ( cnt[0] == 0 && cnt[1] == 0 ) ) ) return cout << "No" << endl , 0;
	dfs(s);
	while ( top ) cout << sta[top--] << ' ';
	return 0;
}

P2731 [USACO3.3] 骑马修栅栏 Riding the Fences

无向图欧拉路

和上一道题不一样的是 这道题需要用map记录边的个数 每走过一条边将这条边和它的反向边都自减 表示删除这条边即可

如果有奇点 那么使它作为起点 否则默认为1即可(实际上默认为任何节点都是等效的)

sort 的目的是让我们保证字典序最小()

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define pii pair<int,int>
#define eb emplace_back
#define mkp make_pair
const int N = 1e3 + 5;
const int inf = 0x3f3f3f3f;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int n , m , s = 1 , maxn , now[N] , sta[N] , top , deg[N];

vector<int> e[N];
void add ( int u , int v ) { e[u].emplace_back(v); }
map<pii,int> mp;

void dfs ( int u )
{
	while(1)
	{
		while ( now[u] < e[u].size() && !mp[mkp(u,e[u][now[u]])] ) now[u] ++;
		if ( now[u] >= e[u].size() ) break;
		int v = e[u][now[u]];
		now[u] ++ , mp[mkp(u,v)] -- , mp[mkp(v,u)] --;
		dfs(v);
	}
	sta[++top] = u;
}

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = 550 , m = read();
	for ( int i = 1 , u , v ; i <= m ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u ) , deg[u] ++ , deg[v] ++ , mp[mkp(u,v)] ++ , mp[mkp(v,u)] ++;
	for ( int i = 1 ; i <= n ; i ++ ) sort ( e[i].begin() , e[i].end() );
	for ( int i = 1 ; i <= n ; i ++ ) if ( deg[i] & 1 ) { s = i; break; }
	dfs(s);
	while ( top ) cout << sta[top--] << endl;
	return 0;
}

P1341 无序字母对

同上一道题 可以暴力开点 直接用ascii值来作为节点编号

注意有cin的地方不能用fread 注意s的初始值 如果是奇点 那么要满足是奇点中编号较小的一个 如果不是 那么必须保证字典序是最小的!

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define mid (l+r>>1)
#define pii pair<int,int>
#define eb emplace_back
#define mkp make_pair
const int N = 125;
const int inf = 0x3f3f3f3f;
//char buf[1<<24] , *p1 , *p2;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f ;
}

int n , m , s , now[N] , sta[N] , top , deg[N] , cnt;

vector<int> e[N];
inl void add ( int u , int v ) { e[u].emplace_back(v); }
map<pii,int> mp;

void dfs ( int u )
{
	while ( 1 )
	{
		while ( now[u] < e[u].size() && !mp[mkp(u,e[u][now[u]])] ) now[u] ++;
		if ( now[u] >= e[u].size() ) break;
		int v = e[u][now[u]];
		now[u] ++ , mp[mkp(u,v)] -- , mp[mkp(v,u)] -- , dfs(v);
	}
	sta[++top] = u;
}

string ss;
signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr) , cout.tie(nullptr);
	n = read();
	for ( int i = 1 , u , v ; i <= n ; i ++ ) cin >> ss , u = (int)(ss[0]) , v = (int)(ss[1]) , add ( u , v ) , add ( v , u ) , deg[u] ++ , deg[v] ++ , mp[mkp(u,v)] ++ , mp[mkp(v,u)] ++;
	for ( int i = 'A' ; i <= 'z' ; i ++ ) { sort ( e[i].begin() , e[i].end() ); if ( deg[i] & 1 ) cnt ++; }
	if ( cnt != 0 && cnt != 2 ) return cout << "No Solution" << endl , 0;
	for ( int i = 'A' ; i <= 'z' ; i ++ ) if ( deg[i] ) { s = i; break; }
	for ( int i = 'A' ; i <= 'z' ; i ++ ) if ( deg[i] & 1 ) { s = i; break; }
	dfs(s);
	if ( top < n + 1 ) return cout << "No Solution" << endl , 0;
	while ( top ) cout << (char)(sta[top--]);
	return 0;
}
posted @   Echo_Long  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示