1 条题解
-
0
欧拉图:欧拉路径(无向图)
【解题思路】
每个字母是一个顶点,每个字母对是一条边。“无序即字母对中的两个字母可以位置颠倒”,意味着这样的边连接的两个字母没有先后顺序,是无向边,形成的图是无向图。
给定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
- 上传者