1 条题解
-
0
自动搬运
来自洛谷,原作者为

Joushi_Ikita
支持壶关//一般不看关注列表,请私信告知//如果你灰了或棕了会取关搬运于
2025-08-24 23:10:54,当前版本为作者最后更新于2025-03-09 21:11:08,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
乍一看被吓到了(雾)正文开始
一、题意:
对于一个 的矩阵,其中填有 到 的 个整数, 相邻两个整数之间有一条边,边权为两数中的较大值(如下)。
长度为 的边 长度为 的边 长度为 的边 长度为 的边 长度为 的边 长度为 的边 长度为 的边 求使最小生成树边权和最小的一种方案(上述情况为 时的一种解,最小生成树如下(不只一种),边权和为 )。
/ 长度为 的边 长度为 的边 长度为 的边 / 长度为 的边 长度为 的边 二、分析:
一般人乍一看应该会和我一样以为要用一些高级的算法或数据结构。
首先考虑到最小生成树的算法之一——Kruskal 的核心思想为贪心,我们可以尝试贪心地去思考问题。
在 Kruskal 中,我们每次都用最短的一条边来将两个点集连接起来,在这个问题中,我们可以将其简化,每次都将一个新的点连到已有的点集上(特别的,点集初始为点 ),易得这条边的边权最小为这个新点的点权。
为使取到这个最小值,这个新点应接到点集中一个点权比它小的点上(这也是为什么点集初始为点 ),不考虑矩阵的结构,连成一条链是最简单的方案(如下)。
1<-->2<-->3<-->4<-->5<-->6
把它放回到矩阵里,就是一个蛇形填数的矩阵(如下(带划掉的是不在链中的边))。长度为 的边 长度为 的边 长度为 的边长度为 的边长度为 的边 长度为 的边 长度为 的边 于是,这题就变成一道简单的蛇形填数了!
代码如下:#include<bits/stdc++.h> using namespace std; int n,m; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(i%2){ cout<<j+(i-1)*m<<' '; } else cout<<i*m-j+1<<' '; } cout<<endl; } return 0; }你以为这就完了?别急,还有优化。
三、优化:
观察到蛇形填数还不够简洁,思考普通填数可否解决。
长度为 的边 长度为 的边 长度为 的边 长度为 的边 长度为 的边 长度为 的边 长度为 的边 观察如上矩阵,发现每行自身满足链状结构,达到局部最优,而将每行第一个数接到上一行第一个数上,依旧满足之前所述的贪心结论,方案可行。
于是我们就得到了最简方案。四、最终代码:
#include<bits/stdc++.h> using namespace std; int n,m; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cout<<j+(i-1)*m<<' '; } cout<<endl; } return 0; }
- 1
信息
- ID
- 11315
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者