news 2026/3/24 11:31:44

繁忙的都市(city)(信息学奥赛一本通- P1392)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
繁忙的都市(city)(信息学奥赛一本通- P1392)

【题目描述】

城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造。城市C的道路是这样分布的:城市中有n个交叉路口,有些交叉路口之间有道路相连,两个交叉路口之间最多有一条道路相连接。这些道路是双向的,且把所有的交叉路口直接或间接的连接起来了。每条道路都有一个分值,分值越小表示这个道路越繁忙,越需要进行改造。但是市政府的资金有限,市长希望进行改造的道路越少越好,于是他提出下面的要求:

1.改造的那些道路能够把所有的交叉路口直接或间接的连通起来。

2.在满足要求1的情况下,改造的道路尽量少。

3.在满足要求1、2的情况下,改造的那些道路中分值最大值尽量小。

作为市规划局的你,应当作出最佳的决策,选择那些道路应当被修建。

【输入】

第一行有两个整数n,m表示城市有n个交叉路口,m条道路。接下来m行是对每条道路的描述,u, v, c表示交叉路口u和v之间有道路相连,分值为c。(1≤n≤300,1≤c≤10000)。

【输出】

两个整数s, max,表示你选出了几条道路,分值最大的那条道路的分值是多少。

【输入样例】

4 5 1 2 3 1 4 5 2 4 7 2 3 6 3 4 8

【输出样例】

3 6

1. 算法分析

这道题看似需要一种特殊的“瓶颈”算法,但实际上,最小生成树 (MST) 本身就满足这个性质

  • MST 的定义是总权值和最小。

  • 推论:MST同时也满足树中最大边权最小

因此,我们只需要跑一遍标准的MST算法(Kruskal或Prim),然后找出树中权值最大的那条边即可。


2. 解法一:Kruskal 算法 (推荐)

核心思路:

Kruskal 算法将所有边按权值从小到大排序。

当我们贪心地选取边加入集合时,最后加入的那条边(第N-1条边),一定是当前生成树中权值最大的边。

代码亮点:

直接输出 mst[cnt].w,无需再次遍历寻找最大值。

//kruskal 核心:排序后,最后加入生成树的边,即为最大权值边。 #include <iostream> #include <algorithm>//sort using namespace std; int n,m; struct edge{ int u,v,w; //重载运算符,按边权从小到大排序 friend bool operator <(edge a,edge b){ return a.w<b.w; } }e[10010];//边集数组 edge mst[10010];//存最小生成树有多少条边 int cnt;//最小生成树边数 long long sum;//最小生成树的长度 int fa[310];//记录每个节点所在集合中的老大 //并查集查询+路径压缩 int find(int x){ if(fa[x]==x) return x;//如果是根节点就返回 //不是就递归找根节点,并把根节点赋给沿途所有节点 return fa[x]=find(fa[x]); } //合并 void uni(int a,int b){ int faa=find(a); int fab=find(b); if(faa!=fab){ fa[fab]=faa; } } void kruskal(){ for(int i=1;i<=m;i++){ int a=e[i].u;//边集数组第i条边一个端点 int b=e[i].v;//边集数组第i条边另外一个端点 if(find(a)!=find(b)){//如果两个端点不在一个集合就链接他们 cnt++; mst[cnt].u=a; mst[cnt].v=b; mst[cnt].w=e[i].w; sum+=e[i].w; uni(a,b); } } } int main(){ cin>>n>>m; //初始化边集数组自成集合,每个点是自己的老大 for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ cin>>e[i].u>>e[i].v>>e[i].w; } //对边集数组按边权从小到大排序 sort(e+1,e+m+1); kruskal(); cout<<cnt<<" "<<mst[cnt].w; }

3. 解法二:堆优化Prim算法

核心思路:

Prim算法通过优先队列每次选择离集合最近的点。

我们需要一个变量ma来记录入队并被选中的边的最大值。

每当一个点被正式加入集合(vis[nid]=1)时,更新 ma=max(ma, dis[nid])。

代码技巧:

cnt 初始化为 -1。因为起点加入集合时不算边,这样当跑完所有点后,cnt 刚好是N-1。

//prim+堆优化 #include <iostream> #include <cstring>//对应memset #include <algorithm>//对应max函数 #include <queue> using namespace std; int n,m; int h[310];//邻接表头指针数组 int vtex[20010];//第i条边的终点下表 int nxt[20010];//与第i条边同起点的下一条边的索引 int wt[20010];//第i条边的边权 int idx; int vis[310];//标记每个点是否已经连通(加入集合) int dis[310];//记录每个点到集合的距离 int cnt=-1;//记录连接上的边数 cnt初始化为-1,就是因为第一个点加入集合不需要边 int ma=0;//记录分值最大的那条道路的分值 long long sum;//最小生成树的总长度 struct node{ int id;//节点编号 int w;//节点权值 //优先队列默认最大堆,重载运算符改为最小堆 离集合最近的点优先出队 friend bool operator<(node a,node b){ return a.w>b.w; } }; priority_queue<node> q; void prim(int s){ dis[s]=0;//起点到自己距离为0 node tmp; tmp.id=s; tmp.w=0; q.push(tmp);//起点入队 while(!q.empty()){ tmp=q.top();//访问队首元素 q.pop();//队首出队 int nid=tmp.id; //如果tmp已经加入集合(出队过)就跳过 if(vis[nid]==1) continue; vis[nid]=1;//否则就链接上 cnt++;//cnt初始化为-1,就是因为第一个点加入集合不需要边 sum+=dis[nid]; ma=max(ma,dis[nid]); int p=h[nid]; while(p!=-1){//遍历tmp的所有邻接点 //如果该临接点尚未加入集合 且目前到集合距离大于经tmp到集合距离 就更新到集合距离 //为经tmp到集合距离 if(vis[vtex[p]]==0 && dis[vtex[p]]>wt[p]){ dis[vtex[p]]=wt[p]; q.push({vtex[p],wt[p]});//然后把这个点入队 } p=nxt[p];//更新指针 } } } void addedge(int u,int v,int w){ vtex[idx]=v; wt[idx]=w; nxt[idx]=h[u]; h[u]=idx++; } int main(){ cin>>n>>m; memset(h,-1,sizeof(h));//初始化头指针数组为空 memset(dis,0x3f,sizeof(dis));//初始化每个点到集合距离为无穷 //邻接表存图 for(int i=1;i<=m;i++){ int u,v,w; cin>>u>>v>>w; addedge(u,v,w);//双向边 addedge(v,u,w); } prim(1);// cout<<cnt<<" "<<ma; return 0; }

4. 总结

算法核心逻辑获取最大边的方式推荐指数
Kruskal边排序+并查集直接取最后一条加入的边 (mst[cnt].w)⭐⭐⭐⭐⭐ (最直观)
Prim优先队列+贪心过程中维护max⭐⭐⭐⭐ (适合稠密图)

这两份代码都已通过测试,是标准的算法模板。对于“瓶颈生成树”类问题,Kruskal 通常更简单直观,因为它天然基于边权排序。

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

博客之星投票啦!

麻烦帮忙投投票呀! 多谢啦! 点击投票!

作者头像 李华
网站建设 2026/3/24 10:07:23

ERNIE 4.5思维版:21B轻量模型推理再进化

ERNIE 4.5思维版&#xff1a;21B轻量模型推理再进化 【免费下载链接】ERNIE-4.5-21B-A3B-Thinking 项目地址: https://ai.gitcode.com/hf_mirrors/baidu/ERNIE-4.5-21B-A3B-Thinking 百度ERNIE系列再推新品——ERNIE-4.5-21B-A3B-Thinking正式发布&#xff0c;这款210亿…

作者头像 李华
网站建设 2026/3/24 9:05:35

GLM-TTS采样率怎么选?24k和32k实测对比

GLM-TTS采样率怎么选&#xff1f;24k和32k实测对比 在语音合成&#xff08;TTS&#xff09;系统中&#xff0c;采样率是影响音频质量与推理效率的关键参数之一。对于支持高质量语音生成的开源模型 GLM-TTS 来说&#xff0c;用户可以在 24kHz 和 32kHz 之间进行选择。但究竟哪个…

作者头像 李华
网站建设 2026/3/23 5:56:04

Sambert多发音人切换教程:知北、知雁情感语音生成案例

Sambert多发音人切换教程&#xff1a;知北、知雁情感语音生成案例 1. 引言 1.1 场景背景与技术需求 在当前智能语音交互系统中&#xff0c;单一音色和固定情感的语音合成已难以满足多样化应用场景的需求。无论是虚拟助手、有声读物&#xff0c;还是客服机器人&#xff0c;用…

作者头像 李华
网站建设 2026/3/22 21:29:42

如何用Z-Image-Turbo生成传统国风画?附详细代码示例

如何用Z-Image-Turbo生成传统国风画&#xff1f;附详细代码示例 1. 引言&#xff1a;AI绘画中的“中国意境”挑战 在当前主流的文生图模型中&#xff0c;生成具有真实中国文化韵味的艺术作品仍是一大难点。许多模型虽然能识别“山水”、“古建筑”等关键词&#xff0c;但往往…

作者头像 李华
网站建设 2026/3/22 6:23:14

量化投资新利器:5分钟构建智能股票筛选系统

量化投资新利器&#xff1a;5分钟构建智能股票筛选系统 【免费下载链接】TradingView-Screener A package that lets you create TradingView screeners in Python 项目地址: https://gitcode.com/gh_mirrors/tr/TradingView-Screener 在当今瞬息万变的金融市场中&#…

作者头像 李华