题目大意原题链接
给若干个单词,判断是否可以把所有单词排成一个序列,序列中每个单词的最后字母与下一个单词的第一个字母相同。例:ACM-MAC-CBA。
de449de6-c455-4619-b317-b84890877ee4
理论基础
欧拉路径: 从图中的一个结点出发走出的一条路径,而且图中的每条边恰好经过一次。
欧拉回路:指起点和终点相同的欧拉路径。
半欧拉图:具有欧拉路径但不具有欧拉回路的图。
存在条件:①忽略边的方向后图是连通的;②对于无向图:有2个或0个奇点(结点度数为奇数);对于有向图:有2个或0个奇点(一个出度必须比入度大1,另一个入度必须比出度大1,分别作为起点和终点)。
解题思路
可将单词的第一个和最后一个字母当成结点,单词看成有向边,所有单词构成一个有向图。若图中存在欧拉路径则问题有解,判断欧拉路径的存在条件是否成立即可。详见代码。
参考代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
#define maxn 26
void dfs(int node, int *vis, int G[][maxn]) {
vis[node] = 1;
for (int i = 0; i < maxn; i++)
if (G[node][i] && !vis[i])
dfs(i, vis, G);
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int in[maxn] = {0}, out[maxn] = {0}, G[maxn][maxn] = {0}, vis[maxn] = {0};
int num1 = 0, num2 = 0, pass = 1, n;
//in、out分别记录结点入度和出度,num1记录入度大1结点个数,num2记录出度大1结点个数
scanf("%d", &n);
while (n--) {
string s;
cin >> s;
out[s[0] - 'a']++; //统计结点入度和出度
in[s[s.size() - 1] - 'a']++;
G[s[0] - 'a'][s[s.size() - 1] - 'a'] = 1;
}
for (int i = 0; i < maxn; i++) { //统计寄点个数
if (in[i] != out[i]) {
if (in[i] == out[i] + 1)
num1++;
else if (out[i] == in[i] + 1)
num2++;
else { //入、出度不符合要求
pass = 0;
break;
}
}
}
if (num1 + num2 > 2) pass = 0; //奇点个数不符合要求
if (pass) {
for (int i = 0; i < maxn; i++) //使用dfs判断图是否连通
if (out[i]) {
dfs(i, vis, G);
break;
}
for (int i = 0; i < maxn; i++) //若每个结点都被访问,则连通,否则不连通
if (out[i] + in[i] > 0 && !vis[i]) {
pass = 0;
break;
}
if (pass)
puts("Ordering is possible.");
else
puts("The door cannot be opened.");
} else
puts("The door cannot be opened.");
}
return 0;
}
分类:
UVA题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效