原题链接:蓝桥杯历届试题-城市建设
解题思路: 看不加码头能不能构成最小生成树,如果不可以,则答案为加上码头和建路的最小生成树, ,,,如果可以,则在不加码头和 加上码头的最小生成树取最小值
注意事项:建议把初始化码头和把码头的边加到边集中写在一个循环,不然会超时
#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、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复