原题链接:蓝桥杯历届试题-城市建设
解题思路: 看不加码头能不能构成最小生成树,如果不可以,则答案为加上码头和建路的最小生成树, ,,,如果可以,则在不加码头和 加上码头的最小生成树取最小值
注意事项:建议把初始化码头和把码头的边加到边集中写在一个循环,不然会超时
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N = 1e4 + 10, M = 1e5 + 10, INF = 0x3f3f3f3f; int p[N], n, m, wi[N]; struct Edge { int a, b, w; //将边集按权值大小排序 bool operator < (const Edge& W)const { return w < W.w; } }e[M]; //并查集 int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } int Kruskal(int node, int length) { int res = 0; //初始化并查集 for (int i = 0; i <= node; i++) p[i] = i; sort(e, e + length); int cnt = 0; for (int i = 0; i < length; i++) { int a = e[i].a, b = e[i].b, c = e[i].w; a = find(a), b = find(b); //如果两个点不连通,将其连起来 if (a!=b) { p[a] = find(b); res += c; cnt++; } //如果两个点连通但是c<0即是赚钱的,也要加上 else if (c < 0) res += c; } //如果不能构成连通图,则返回INF if (cnt < n - 1) return INF; return res; } int main() { scanf("%d %d", &n, &m); int cnt = m, ans; //边集初始化 for (int i = 0; i < m; i++) { int x, y, w; scanf("%d %d %d", &x, &y, &w); e[i] = { x,y,w }; } int t = Kruskal(n, m); //加上码头 for (int i = 1; i <= n; i++) { scanf("%d", &wi[i]); if (wi[i] != -1) { e[cnt].a = 0; e[cnt].b = i; e[cnt].w = wi[i]; cnt++; } } //建路构成不了连通图,此时要加上码头 if (t == INF) { ans = Kruskal(n + 1, cnt); } //建路可以构成联通图,则在两个结果中取小的 else { ans = min(t, Kruskal(n + 1, cnt)); } cout << ans << endl; return 0; }
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复