题解:P5687 [CSP-S2019 江西] 网格图
HZY1618yzh · · 题解
题目传送门
题意
给定一个
- 横向边:第
i 行相邻的点之间有一条边,权值为a_i 。 - 纵向边:第
j 列相邻的点之间有一条边,权值为b_j 。
要求:求出这个网格图的最小生成树(即用最少的边权总和连接所有点)。
解决方法
要求最少的边权总和连接所有点,所以需要贪心使得当前边权尽量小,因此需要排序。
不难证明,
注:后面讲解里,我们令权值越小的横向边(
网格图一共有
不过这样这棵树,却变成了一层又一层的“厂”,并不联通。所以我们可以每层挑选
不过这是最优的贪心策略吗?大胆猜测,小心求证。如果
我们可以先确定
选择剩下边里最小可以用双指针实现,每个指针表示的是当前正在选第几条边(即
语言代码:
- 输入。
- 对
a 和b 数组排序。 - 取
a_1 和b_1 (最小的)作为基础边,增加给ans 。 - 然后利用双指针实现
ans 交替增加较小的a_i 、b_j 乘以剩余需要的边数。 - 输出答案。
具体实现
- c++
#include<bits/stdc++.h> using namespace std; using ll = long long; int n,m,a[300001],b[300001]; ll ans; int main(){ cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++) cin>>b[i]; //排序 sort(a+1,a+n+1); sort(b+1,b+m+1); ans=(ll)a[1]*(m-1)+(ll)b[1]*(n-1);//取a_1和b_1(最小的)作为基础边 int i=2,j=2; while(i<=n&&j<=m){ if(a[i]<b[j]){//取较小的a_i或b_j ans+=(ll)a[i]*(m-j+1);//乘以剩余需要的边数 i++;//移动指针 }else{ ans+=(ll)b[j]*(n-i+1);//乘以剩余需要的边数 j++;//移动指针 } } cout<<ans; return 0; } - python
n,m=map(int,input().split()) a=list(map(int, input().split())) b=list(map(int, input().split()) a.sort() b.sort() ans=a[0]*(m-1)+b[0]*(n-1) i,j=1,1 while i<n and j<m: if a[i]<b[j]: ans+=a[i]*(m-j) i+=1 else: ans+=b[j]*(n-i) j+=1 print(ans)~给个赞吧!~