2022.9.9 360笔试题-老张修路
给出点与边的关系及边的权值,求最小生成树的最小权值之和
测试用例:
3 3 1 1 2 2 3 3 885 513 817
样例输出:
1330
邻接矩阵 + prim
#include<iostream>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
using namespace std;
int main() {
//n代表结点个数,m代表边的个数
int n, m;
cin >> n >> m;
int u, v;//入边,出边
vector<vector<int>> nums(3, vector<int>(m));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < m; j++) {
cin >> nums[i][j];
}
}
//邻接矩阵
vector<vector<int>> edge(n, vector<int>(n));
for (int i = 0; i < m; ++i) {
edge[nums[0][i] - 1][nums[1][i] - 1] = nums[2][i];
edge[nums[1][i] - 1][nums[0][i] - 1] = edge[nums[0][i] - 1][nums[1][i] - 1];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << edge[i][j] << " ";
}
cout << endl;
}
unordered_map<int, int> mp;//存已经加入的边
vector<int> vt;
//prim开始
mp[0] = 1;
vt.push_back(0);
int ans = 0;
int minLen;
int node;
for (int i = 0; i < n - 1; ++i) {
minLen = INT_MAX;
node = -1;
for (auto e1 : vt) {//for e1 in vt,离已选点最近的点加进来
for (int k = 0; k < n; ++k) {
if (mp[k]) continue;
else if (edge[e1][k] == 0) continue;//无边
else {
if (edge[e1][k] < minLen) {
node = k;
minLen = edge[e1][k];
}
}
}
}
ans += minLen;
mp[node] = 1;
vt.push_back(node);
}
cout << ans << endl;
return 0;
}
邻接表 + prim
#include<iostream>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
using namespace std;
struct Edge;
struct Node {
int val;
vector<Node*> next;
vector<Edge*> edges;
Node(int val) {
this->val = val;
}
};
struct Edge {
Node* from;
Node* to;
int weight;
Edge(int w, Node* f, Node* t) {
weight = w;
from = f;
to = t;
}
};
struct queue_cmp {
bool operator() (Edge* a, Edge* b) {
return a->weight > b->weight;
}
};
int main() {
//n代表结点个数,m代表边的个数
int n, m;
cin >> n >> m;
vector<vector<int>> nums(3, vector<int>(m));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < m; j++) {
cin >> nums[i][j];
}
}
//记录点集
unordered_map<int, Node*> nodes;
//记录边集
unordered_set<Edge*> edges;
//入边,出边,权值
int from, to, weight;
//创建邻接表
for (int i = 0; i < m; i++) {
from = nums[0][i];
to = nums[1][i];
weight = nums[2][i];
if (nodes.find(from) == nodes.end()) {
Node* node = new Node(from);
nodes[from] = node;
}
if (nodes.find(to) == nodes.end()) {
Node* node = new Node(to);
nodes[to] = node;
}
Node* nodeFrom = nodes[from];
Node* nodeTo = nodes[to];
//无向图,输入时创建两条相互边
Edge* edge1 = new Edge(weight, nodeFrom, nodeTo);
edges.insert(edge1);
Edge* edge2 = new Edge(weight, nodeTo, nodeFrom);
edges.insert(edge2);
nodeFrom->next.push_back(nodeTo);
nodeFrom->edges.push_back(edge1);
nodeTo->next.push_back(nodeFrom);
nodeTo->edges.push_back(edge2);
}
//prim算法
int res = 0;
unordered_set<Node*> markedNodes;
priority_queue<Edge*, vector<Edge*>, queue_cmp> pQueue;
//从0开始遍历点集,先将以0为入边的边都放入优先级队列中并标记
for (int i = 0; i < nodes[1]->edges.size(); i++) {
pQueue.push(nodes[1]->edges[i]);
}
markedNodes.insert(nodes[1]);
while (markedNodes.size() < nodes.size()) {
Edge* minEdge = pQueue.top();
pQueue.pop();
if (markedNodes.find(minEdge->to) == markedNodes.end()) {
res += minEdge->weight;
markedNodes.insert(minEdge->to);
}
for (int i = 0; i < minEdge->to->edges.size(); i++) {
if (markedNodes.find(minEdge->to->edges[i]->to) == markedNodes.end()) {
pQueue.push(minEdge->to->edges[i]);
}
}
}
cout << res << endl;
return 0;
}