当前位置: 首页 > article >正文

洛谷 P1341 无序字母对

【题目链接】

洛谷 P1341 无序字母对

【题目考点】

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

【解题思路】

每个字母是一个顶点,每个字母对是一条边。“无序即字母对中的两个字母可以位置颠倒”,意味着这样的边连接的两个字母没有先后顺序,是无向边,形成的图是无向图。
给定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;
}

http://www.kler.cn/a/9908.html

相关文章:

  • 记录使用documents4j来将word文件转化为pdf文件
  • Bugku CTF_Web——文件上传
  • LabVIEW开发相机与显微镜自动对焦功能
  • ssm100医学生在线学习交流平台+vue(论文+源码)_kaic
  • gdb编译教程(支持linux下X86和ARM架构)
  • 闯关leetcode——3174. Clear Digits
  • Monitor方案MT9800学习笔记(三) —— 点屏(V-by-One信号接口)
  • MybatisPlus <= 3.5.3.1 TenantPlugin 组件 存在 sql 注入漏洞(CVE-2023-25330)
  • 测试:腾讯云轻量4核8G12M服务器CPU流量带宽系统盘
  • pytorch进阶学习(三):在数据集数量不够时如何进行数据增强
  • 花30分钟,我用ChatGPT写了一篇2000字文章(内附实操过程)
  • 【LeetCode】剑指 Offer 49. 丑数 p240 -- Java Version
  • JavaScript 基础入门速成上篇
  • GPT、科技、人类的生产、知识与未来(下)
  • IO流复习
  • 算法题:图的表示形式与遍历框架
  • k8s 磁盘不够用,docker数据迁移 导致 /tmp Permission denied,docker优化日志 日志切割, 日志自动删除
  • 小米手机root后过软件检测
  • Flink (十) --------- 容错机制
  • ActiveMQ使用(二):在JavaScript中使用mqtt.js
  • 和开振学Spring boot 3.0之Spring MVC:④获取参数(上)
  • 《Java8实战》第1章 Java 8、9、10 以及 11 的变化
  • 小程序的组件化开发
  • 图的遍历及连通性
  • Spark 简介与原理
  • 2023年网络安全HW面试经典收藏