news 2026/6/9 20:58:25

【例4-8】格子游戏(信息学奥赛一本通- P1347)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【例4-8】格子游戏(信息学奥赛一本通- P1347)

【题目描述】

Alice和Bob玩了一个古老的游戏:首先画一个n × n的点阵(下图n = 3)

接着,他们两个轮流在相邻的点之间画上红边和蓝边:

直到围成一个封闭的圈(面积不必为1)为止,“封圈”的那个人就是赢家。因为棋盘实在是太大了(n ≤ 200),他们的游戏实在是太长了!他们甚至在游戏中都不知道谁赢得了游戏。于是请你写一个程序,帮助他们计算他们是否结束了游戏?

【输入】

输入数据第一行为两个整数n和m。m表示一共画了m条线。以后m行,每行首先有两个数字(x, y),代表了画线的起点坐标,接着用空格隔开一个字符,假如字符是"D ",则是向下连一条边,如果是"R "就是向右连一条边。输入数据不会有重复的边且保证正确。

【输出】

输出一行:在第几步的时候结束。假如m步之后也没有结束,则输出一行“draw”。

【输入样例】

3 5 1 1 D 1 1 R 1 2 D 2 1 R 2 2 D

【输出样例】

4

1. 题目背景与算法模型

核心问题:在一个N*N的网格图中,判断哪一步连边操作后首次形成环。

算法模型:连通性维护与判环,首选并查集。


2. 解法一:基于 STL 的直接存储法 (Map + Pair)

此方法无需推导坐标映射公式,适合处理稀疏图或非标准网格

完整代码

//这道题首先应想到当画一条边前如果find(u)==find(v)了,那么这条边一画 //就成环了,就结束游戏了,然后就是想着如何存坐标 两种方式 //第一种直接用pair或者结构体struct自己写一个pair然后存入map,但是map是会对键自动排序的 //所以如果用pair就不用管,因为pair会按照字典序自动排序,但如果自己写结构体 就要重载一下运算符 //第二种直接把二维坐标转换成一维数字,把每一个坐标都用一个数字替换 //pair写法 #include <bits/stdc++.h> #include <algorithm> #include <map> using namespace std; int n,m; //定义类型别名,避免后续反复书写pair<int,int> typedef pair<int,int> pii; pii p1; pii p2; map<pii,pii> fa;//fa存每个坐标的父/祖先节点 pii find(pii x){ if(fa[x]==x) return x;//如果已经是祖先/根结点 返回 //否则就递归找祖先 并进行路径压缩 return fa[x]=find(fa[x]); } void uni(pii x,pii y){ pii fax=find(x);//x的祖先节点 pii fay=find(y);//y的祖先节点 //如果相等说明在一个集合 无事发生,不相等就让fax成为fay的老大的老大 if(fax!=fay){ fa[fay]=fax; } } int main(){ cin>>n>>m; for(int i=1;i<=m;i++){ int x,y; char c; cin>>x>>y>>c; p1={x,y}; if(c=='D')//向下 p2={x+1,y}; else//向右 p2={x,y+1}; //如果p1 p2还没有父节点,就初始化父节点为自己 if(!fa.count(p1)) fa[p1]=p1; if(!fa.count(p2)) fa[p2]=p2; //当画一条边前如果find(u)已经==find(v)了,那么这条边一画 就成环了 if(find(p1)==find(p2)){ cout<<i; return 0; } uni(p1,p2); } cout<<"draw"; return 0; }

3. 解法二:二维坐标转化为一位标记的数组法

这是竞赛中的标准解法,通过ID = (x-1)*N+y将二维坐标映射为一维,效率最高。

//第二种方法二维坐标用一维数字代替,节省大量代码 #include <bits/stdc++.h> using namespace std; int n,m; int fa[40010]; //二维坐标压缩成一维标记 int getid(int x,int y){ return (x-1)*n+y; } int find(int x){ if(fa[x]==x) return x;//如果已经是祖先/根结点 返回 //否则就递归找祖先 并进行路径压缩 return fa[x]=find(fa[x]); } void uni(int x,int y){ int fax=find(x);//x的祖先节点 int fay=find(y);//y的祖先节点 //如果相等说明在一个集合 无事发生,不相等就让fax成为fay的老大的老大 if(fax!=fay){ fa[fay]=fax; } } int main(){ cin>>n>>m; //初始化自己的祖先为自己 for(int i=1;i<=n*n;i++) fa[i]=i; for(int i=1;i<=m;i++){ int x,y; char c; cin>>x>>y>>c; int p1=getid(x,y); int p2=-1; if(c=='D')//向下 p2=getid(x+1,y); else//向右 p2=getid(x,y+1); //如果p1 p2还没有父节点,就初始化父节点为自己 //当画一条边前如果find(u)已经==find(v)了,那么这条边一画 就成环了 if(find(p1)==find(p2)){ cout<<i; return 0; } uni(p1,p2); } cout<<"draw"; return 0; }

4. 关键复盘:STL 写法中的严重易错点

在使用第一种方法(Map + Pair)时,许多同学会因为不熟悉 C++ 强类型机制而遭遇编译错误或逻辑异常。以下是必须规避的三个核心错误:

易错点 1:错误使用 Pair 作为类型名会导致信息学奥赛一本通system error

这是新手最容易犯的语法错误。

  • 错误写法

    pair p1; // ❌ 错误:缺少模板参数 pair find(pair x) { // ❌ 错误:编译器无法推断 pair 内部存什么 ... }
  • 错误原因std::pair本质上是一个类模板,而非具体的类型 (Type)。它就像一个模具,必须明确告诉编译器里面装的是intdouble还是string,编译器才能生成具体的代码。

  • 正确写法:必须显式指定模板参数。

    pair<int,int> p1; // ✅ 正确 pair<int,int> find(pair<int,int> x) { ... } // ✅ 正确
  • 优化建议:使用typedefusing简化代码。

    typedef pair<int,int> pii; pii find(pii x) { ... }
易错点 2:Map 的自动构造陷阱
  • 错误现象:没有对 map 进行初始化,直接在find函数中访问fa[x]

  • 后果:当访问不存在的键时,std::map会自动插入该键,并将其值初始化为默认值({0,0})。这会导致所有未手动初始化的节点,其父节点都被错误地指向{0,0},破坏并查集的树形结构。

  • 修正方案:在调用find前,必须使用if(!fa.count(p))检查并手动初始化fa[p] = p;

易错点 3:并查集路径压缩的浅拷贝问题
  • 错误写法void uni(pii x,pii y) {fa[y]=fa[x];}

  • 分析:这行代码并没有去寻找xy的根节点(祖宗),仅仅是将y的父节点修改了。这在路径压缩未完成时是错误的,会导致集合无法正确合并。

  • 正确写法:必须调用find函数获取根节点。

    pii fax=find(x); pii fay=find(y); if(fax!=fay) fa[fay]=fax;

5. 总结

本题通过两种解法展示了数据结构选择的权衡:

  1. 数组法:利用数学映射实现O(1)访问,是处理标准网格图的最优解

  2. STL 法:代码逻辑直观,但要求对C++ 模板语法容器机制有一定理解,否则极易出现编译错误或隐蔽的运行时错误。

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

python基于flask框架的健身运动比赛服务饮食推荐平台设计与实现

目录摘要开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;摘要 健身运动比赛服务饮食推荐平台基于Flask框架设计&#xff0c;旨在为运动员和健身爱好者提供个性化的饮食建议与赛事服务。平台…

作者头像 李华
网站建设 2026/6/9 16:14:04

炉石传说脚本完整使用指南:从零基础到精通

炉石传说脚本完整使用指南&#xff1a;从零基础到精通 【免费下载链接】Hearthstone-Script Hearthstone script&#xff08;炉石传说脚本&#xff09;&#xff08;2024.01.25停更至国服回归&#xff09; 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script …

作者头像 李华
网站建设 2026/6/9 16:13:08

RAG优化策略终极指南:17种方法全对比+选型建议,开发者必藏!

文章详细解析了RAG系统的17种优化策略&#xff0c;包括基础检索、语义切分、小块查大块答等方法&#xff0c;对比各策略的检索精度、响应速度和技术成本&#xff0c;并通过GPT评分评估效果。文章提供了基于应用场景和数据特征的选型建议&#xff0c;帮助开发者根据精度需求和预…

作者头像 李华
网站建设 2026/6/9 16:11:01

MySQL数据可视化实战指南

MySQL 数据可视化的基础概念数据可视化与MySQL的关系&#xff1a;MySQL作为数据存储工具&#xff0c;如何为可视化提供结构化数据常见可视化场景&#xff1a;报表、仪表盘、趋势分析等关键工具与技术栈&#xff1a;MySQL 可视化工具&#xff08;如Tableau、Power BI、Metabase…

作者头像 李华
网站建设 2026/6/9 16:12:30

玩转Linux命令:创意组合大赛全攻略

Linux命令创意组合大赛技术文章大纲大赛背景与意义Linux命令组合的灵活性与强大功能 创意组合在实际运维、开发中的价值 大赛对技术社区和技能提升的推动作用参赛要求与规则参赛者需使用基础Linux命令进行组合 禁止使用危险命令&#xff08;如rm -rf /&#xff09; 评判标准&am…

作者头像 李华
网站建设 2026/6/9 17:25:23

如何在3分钟内为Windows 11 LTSC系统安装微软商店:完整指南

如何在3分钟内为Windows 11 LTSC系统安装微软商店&#xff1a;完整指南 【免费下载链接】LTSC-Add-MicrosoftStore Add Windows Store to Windows 11 24H2 LTSC 项目地址: https://gitcode.com/gh_mirrors/ltscad/LTSC-Add-MicrosoftStore 当你在使用Windows 11 LTSC企业…

作者头像 李华