1 条题解

  • 0
    @ 2025-8-12 3:12:26

    欧拉图:欧拉路径(无向图)

    【解题思路】

    每个字母是一个顶点,每个字母对是一条边“无序即字母对中的两个字母可以位置颠倒”,意味着这样的边连接的两个字母没有先后顺序,是无向边,形成的图是无向图。
    给定n个不同的字母对,也就是n个不同的边(没有重边),要得到一个有n+1个字母的字符串,每个字母对都出现。相邻两个字母是一个字母对,n+1个字母的字符串中可以出现n个字母对,也就是说给定的n个字母对都要出现。

    该字符串相当于图中的一条路径,字符串中相邻的字母构成的字母对是一条边。要想让所有字母对都出现,也就是该路径要经过图中所有的边,即该路径是欧拉路径。

    该问题抽象为:每个字母是一个顶点,每个字母对是一条边,求该无向图中的欧拉路径。

    大写与小写字母的ASCII码在0~127范围内,可以直接用字母的ASCII码作为该字母对应顶点的编号。

    判断无向图有欧拉路径的条件

    • 所有顶点都是偶数度
    • 只有两个顶点是奇数度,其它顶点是偶数度
    • 输入边的同时,统计顶点的度。
    • 遍历所有顶点,统计度为奇数的顶点数。
    • 由于要求输出字典序最小的方案,因此必须选择可能作为起点的编号最小的顶点。
      如果所有顶点都是偶数度,那么按编号从小到大遍历所有顶点,选择第一个度大于0的顶点作为起点 如果存在两个度为奇数的顶点,那么按编号从小到大遍历所有顶点,选择第一个奇数度顶点作为起点 对于其它情况,该图不存在欧拉路径,输出"No Solution"
      从起点出发,调用Hierholzer算法,求出欧拉路径,最后把欧拉路径转化成字符串输出。

    【题解代码】

    写法1:使用邻接矩阵

    #include <bits/stdc++.h>
    using namespace std;
    #define N 128
    int m, n = 128, edge[N][N], deg[N];
    stack<char> stk;
    void dfs(int u)
    {
    	for(int v = 0; v < n; ++v)
    	{
    		if(edge[u][v])
    		{
    			edge[u][v] = edge[v][u] = 0;
    			dfs(v); 
    		}
    	}
    	stk.push(u);
    } 
    int main()
    {
    	int oddNum = 0;//奇数度顶点数量 
    	char f, t, st;
    	cin >> m;
    	for(int i = 1; i <= m; ++i)
    	{
    		cin >> f >> t;//scanf("%c%c\n", &f, &t);
    		edge[f][t] = edge[t][f] = 1;//无重边 
    		deg[f]++, deg[t]++;
    	}
    	for(int v = 0; v < n; ++v)
    		if(deg[v] > 0 && deg[v]%2 == 1)
    			oddNum++;
    	if(oddNum == 0)//有欧拉回路 
    	{
    		for(int v = 0; v < n; ++v)
    			if(deg[v] > 0)
    			{
    				st = v;
    				break;
    			}
    	}
    	else if(oddNum == 2)//有欧拉路径
    	{
    		for(int v = 0; v < n; ++v)
    			if(deg[v]%2 == 1)
    			{
    				st = v;
    				break;
    			}
    	}
    	else
    	{
    		cout << "No Solution";
    		return 0;
    	}
    	dfs(st);
    	while(stk.empty() == false)
    	{
    		cout << stk.top();
    		stk.pop();
    	}
    	return 0;
    }
    
    

    写法2:使用邻接表

    #include<bits/stdc++.h>
    using namespace std;
    #define N 130
    #define M 1330 //边最大数量,为52个结点中选两个连边的数量:C(52, 2) = 1326
    struct Node
    {
    	int v, e;//v:顶点编号 e:边编号 
    	Node(){}
    	Node(int a, int b):v(a), e(b){}
    	bool operator < (Node b)
    	{
    		return v < b.v;
    	}
    };
    int n, deg[N], beg[N];//beg[i]:edge[i]从下标beg[i]开始,下标更前面的顶点相当于已被删掉
    vector<Node> edge[N];
    bool vis[M]; 
    stack<char> stk;
    void dfs(int u)
    {
    	for(int &i = beg[u]; i < edge[u].size(); ++i)
    	{
    		int v = edge[u][i].v, e = edge[u][i].e;
    		if(vis[e] == false)
    		{
    			vis[e] = true;
    			dfs(v);
    		}
    	}
    	stk.push(u);
    }
    int main()
    {
    	char f, t, st;
    	int oddNum = 0;//奇数度顶点数量 
    	cin >> n;
    	for(int i = 1; i <= n; ++i)
    	{
    		cin >> f >> t;
    		edge[f].push_back(Node(t, i));
    		edge[t].push_back(Node(f, i));
    		deg[f]++, deg[t]++;
    	}
    	for(int i = 0; i < 128; ++i)
    		sort(edge[i].begin(), edge[i].end());//使每个vector有序,以输出字典序最小的序列。
    	for(int v = 0; v < 128; ++v)
    		if(deg[v]%2 == 1)
    			oddNum++;
    	if(oddNum == 0)
    	{
    		for(int v = 0; v < 128; ++v)
    			if(deg[v] > 0)
    			{
    				st = v;
    				break;
    			}
    	}
    	else if(oddNum == 2)
    	{
    		for(int v = 0; v < 128; ++v)
    			if(deg[v]%2 == 1)
    			{
    				st = v;
    				break;
    			}
    	}
    	else
    	{
    		cout << "No Solution";
    		return 0;
    	}
    	dfs(st);
    	while(stk.empty() == false)
    	{
    		cout << stk.top();
    		stk.pop();
    	}
    	return 0;
    }
    
    
    • 1

    信息

    ID
    4819
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    4
    已通过
    1
    上传者