news 2026/6/22 13:28:41

骑马修栅栏(fence)(信息学奥赛一本通- P1375)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
骑马修栅栏(fence)(信息学奥赛一本通- P1375)

【题目描述】

农民John每年有很多栅栏要修理。他总是骑着马穿过每一个栅栏并修复它破损的地方。

John是一个与其他农民一样懒的人。他讨厌骑马,因此从来不两次经过一个一个栅栏。你必须编一个程序,读入栅栏网络的描述,并计算出一条修栅栏的路径,使每个栅栏都恰好被经过一次。John能从任何一个顶点(即两个栅栏的交点)开始骑马,在任意一个顶点结束。

每一个栅栏连接两个顶点,顶点用1到500标号(虽然有的农场并没有500个顶点)。一个顶点上可连接任意多(≥1)个栅栏。所有栅栏都是连通的(也就是你可以从任意一个栅栏到达另外的所有栅栏)。

你的程序必须输出骑马的路径(用路上依次经过的顶点号码表示)。我们如果把输出的路径看成是一个500进制的数,那么当存在多组解的情况下,输出500进制表示法中最小的一个 (也就是输出第一个数较小的,如果还有多组解,输出第二个数较小的,等等)。 输入数据保证至少有一个解。

【输入】

第1行:一个整数F(1≤F≤1024),表示栅栏的数目;

第2到F+1行:每行两个整数i,j(1≤=i,j≤500)表示这条栅栏连接i与j号顶点。

【输出】

输出应当有F+1行,每行一个整数,依次表示路径经过的顶点号。注意数据可能有多组解,但是只有上面题目要求的那一组解是认为正确的。

【输入样例】

9 1 2 2 3 3 4 4 2 4 5 2 5 5 6 5 7 4 6

【输出样例】

1 2 3 4 2 5 4 6 5 7
1. 什么是欧拉路(一笔画)?

简单来说,就是“走完所有的边,且每条边只走一次”。

  • 如果能回到起点,叫欧拉回路

  • 如果回不到起点,叫欧拉通路

做这种题,别去脑补怎么画,直接套用Hierholzer 算法(DFS + 栈)

2. 踩坑提醒:这两个地方最容易wa

刚才做题时,我有两个地方写错了,调了半天才发现。这两个坑非常典型,同学们一定要注意:

易错点一:邻接矩阵要存“数量”而不是“状态”

  • 错误写法g[u][v] = 1;

  • 原因:题目中两个点之间可能有多条边(比如 1 和 2 之间有两道栅栏)。如果只存 1,就会覆盖掉之前的边,导致少走一条路。

  • 正确写法:用g[u][v]++累加边的数量,删边时用g[u][v]--

易错点二:起点的选择逻辑

  • 错误写法:只找奇点(度数为奇数的点)出发,找不到就直接结束。

  • 原因:如果是一张欧拉回路图(所有点度数都是偶数),循环里根本找不到奇点,程序会没有任何输出。

  • 正确写法

    1. 优先找奇点(如果有,一定是 2 个,选编号小的那个)。

    2. 如果没找到奇点,说明是回路,默认从编号最小的有边节点(通常是 1)出发。

3. 核心算法逻辑

不要在“进递归”的时候输出,要在“回溯”(路走不通了要退回来)的时候把点记录下来。

因为我们是在“退回来”的时候记录的,所以路径是倒序的。

解决办法:用一个 栈把点存进去,最后弹出来就是正序路径。

4.完整代码
#include <iostream> #include <stack> //因为是倒着回溯输出的,所以输出与路线刚好相反,就存进栈 using namespace std; int g[510][510]; int d[510];//记录每个节点连接的边数 int ma=1;//记录有多少个点 stack<int> s; void dfs(int x){ for(int i=1;i<=ma;i++){ if(g[x][i]>0){//如果有栅栏就必须走 g[x][i]--;//然后把栅栏标记为走过 g[i][x]--; dfs(i); } } //路走完了,回溯时进栈 s.push(x); } int main(){ int f; cin>>f; for(int i=1;i<=f;i++){ int u,v; cin>>u>>v;//栅栏是双向的 g[u][v]++;//容易出错的地方 可能不止一个栅栏 g[v][u]++; d[u]++; d[v]++; ma=max(ma,u); ma=max(ma,v); } for(int i=1;i<=ma;i++){ if(d[i]%2==1){//如果是欧拉通路 无向图一笔画要从连接奇数个边的点作为起点 dfs(i); while(!s.empty()){//栈先入后出原则 刚好把倒着存进去的按照正确路线输出 cout<<s.top()<<endl; s.pop(); } return 0; } } //没有找到连接奇数个边的点就是欧拉回路 dfs(1); while(!s.empty()){//栈先入后出原则 刚好把倒着存进去的按照正确路线输出 cout<<s.top()<<endl; s.pop(); } return 0; }
5. 总结

遇到“经过所有边”的题:

  1. 先看度数判断能不能画出来(奇点只能是 0 个或 2 个)。

  2. 用邻接矩阵++存边,防重边。

  3. DFS 回溯入栈,最后倒序输出。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 7:48:43

终极解决方案:快速修复DBeaver SQL自动补全失效问题

终极解决方案&#xff1a;快速修复DBeaver SQL自动补全失效问题 【免费下载链接】dbeaver DBeaver 是一个通用的数据库管理工具&#xff0c;支持跨平台使用。* 支持多种数据库类型&#xff0c;如 MySQL、PostgreSQL、MongoDB 等&#xff1b;提供 SQL 编辑、查询、调试等功能&am…

作者头像 李华
网站建设 2026/6/13 15:26:39

完整示例展示STLink引脚图到PCB封装设计

从STLink引脚图到PCB封装&#xff1a;一次成功的硬件设计实战在嵌入式开发的世界里&#xff0c;调试接口就像工程师的“听诊器”——没有它&#xff0c;再精巧的电路也难以排查问题。而STLink作为STM32生态中最常用的调试工具&#xff0c;几乎出现在每一块评估板、开发板甚至量…

作者头像 李华
网站建设 2026/6/18 18:25:41

AD20与AD23元件库兼容性解析:项目迁移核心要点

AD20到AD23元件库迁移实战&#xff1a;绕过“封装丢失”与“参数异常”的那些坑你有没有遇到过这样的场景&#xff1f;一个在AD20里运行得好好的项目&#xff0c;信心满满地打开Altium Designer 23准备继续开发——结果一编译&#xff0c;满屏红色警告&#xff1a;“Component …

作者头像 李华
网站建设 2026/6/12 19:57:50

3分钟掌握AI分镜技巧:Qwen-Image-Edit 2509让电影创作效率提升300%

3分钟掌握AI分镜技巧&#xff1a;Qwen-Image-Edit 2509让电影创作效率提升300% 【免费下载链接】next-scene-qwen-image-lora-2509 项目地址: https://ai.gitcode.com/hf_mirrors/lovis93/next-scene-qwen-image-lora-2509 还在为分镜制作而苦恼吗&#xff1f;想象一下…

作者头像 李华
网站建设 2026/6/20 4:01:23

AI 背景移除器:释放图像创意的无限可能

在当今这个视觉主导的时代&#xff0c;一张干净、专业的图片往往能瞬间抓住人们的眼球。无论是设计海报、制作电商产品图&#xff0c;还是进行创意合成&#xff0c;去除图片中复杂或不相关的背景&#xff0c;让主体脱颖而出&#xff0c;已成为一项关键且高频的需求。然而&#…

作者头像 李华
网站建设 2026/6/13 5:39:27

CSRF跨站请求伪造,零基础入门到精通,收藏这篇就够了

一、CSRF漏洞原理 我们不能挟持用户&#xff0c;但是我们可以挟持用户的浏览器发送任意的请求。某些html标签是可以发送HTTP GET类型的请求的。 例如<img>标签&#xff1a;<img src"http://www.baidu.com" /> 浏览器渲染img标签的时候&#xff0c;并不知…

作者头像 李华