题目描述
时间限制: 600 ms 内存限制: 8000 kb
EA出品的模拟经营类游戏《模拟城市》,想必好多人都玩过的吧~
Jeffrey虽然喜欢玩,但不代表他是一个好玩家。现在Jeffrey的模拟城市已经濒临破产,原因很简单:他太爱修路了!
悬崖勒马,现在他想保留一些道路,拆除其余的道路,要求是在保证城市的每个区域互相连通的基础上,使道路的总维护费用最小。
为简化问题,假设所有道路每单位长度的维护费用为1。数据保证整个模拟城市是一个连通图。
输入
多组测试数据。 每组数据第一行是两个整数,分别表示有n个区域,m条道路。(1≤n≤103,0≤m≤105)
接下来m行,每行三个整数u、v、l,表示区域u和区域v之间有一条长度为l的双向道路。(1≤u,v≤n,1≤l≤100)
输出
对于每组数据,输出最小总维护费用。
输入样例
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
输出样例
15
思路
最小生成树
代码
prim+堆优化
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
struct mstNode {
int head;
int tail;
int weight;
explicit mstNode(int h = -1, int t = -1, int w = -1) : head(h), tail(t), weight(w) {}
bool operator>(const mstNode &p) const {
return weight > p.weight;
}
};
struct node {
int rank;
int weight;
explicit node(int r = -1, int w = -1) : rank(r), weight(w) {}
};
int n, m;
ll sum;
vector<node> matrix[1001];
inline void prim(int v0) {
int v, count;
mstNode selected;
priority_queue<mstNode, vector<mstNode>, greater<mstNode> > minHeap;
bool vOfmst[n + 1];
memset(vOfmst, 0, sizeof(vOfmst));
vOfmst[v0] = true;
count = 1;
v = v0;
sum = 0;
while (count < n) {
for (int i = 0, size = (int) matrix[v].size(); i < size; ++i)
if (!vOfmst[matrix[v][i].rank])
minHeap.push(mstNode(v, matrix[v][i].rank, matrix[v][i].weight));
again:
selected = minHeap.top();
minHeap.pop();
if (!vOfmst[selected.tail]) {
sum += selected.weight;
++count;
vOfmst[selected.tail] = true;
} else goto again;
v = selected.tail;
}
}
int main() {
int u, v, w;
while (~scanf("%d%d", &n, &m)) {
for (int i = 0; i < m; ++i) {
scanf("%d%d%d", &u, &v, &w);
matrix[u].emplace_back(v, w);
matrix[v].emplace_back(u, w);
}
prim(1);
printf("%lld\n", sum);
for (int i = 1; i <= n; i++)
matrix[i].clear();
}
}
Kruskal
#include <cstdio>
#include <algorithm>
#define MAXN 100005
using namespace std;
int num_V, num_E, ans;
struct Node {
int to, from, cost;
} road[MAXN];
int Par[MAXN];
bool cmp(const Node &a, const Node &b) {
return (a.cost < b.cost);
}
void init() {
for (int i = 0; i < num_E; i++) Par[i] = -1;
}
int Find(int x) {
int root = x;
while (Par[root] >= 0) root = Par[root];
return root;
}
void unite(int x, int y) {
x = Find(x);
y = Find(y);
if (Par[x] < Par[y]) {
Par[x] += Par[y];
Par[y] = x;
} else {
Par[y] += Par[x];
Par[x] = y;
}
}
int kruskal() {
int nEdge = 0, fees = 0;
for (int i = 0; i < num_E && nEdge != num_V - 1; i++) {
if (Find(road[i].from) != Find(road[i].to)) {
unite(road[i].from, road[i].to);
fees += road[i].cost;
nEdge++;
}
}
return fees;
}
int main() {
while (~scanf("%d%d", &num_V, &num_E)) {
init();
for (int i = 0; i < num_E; i++) {
scanf("%d%d%d", &road[i].from, &road[i].to, &road[i].cost);
}
sort(road, road + num_E, cmp);
ans = kruskal();
printf("%d\n", ans);
}
}