2022.9.9 360笔试题-老张修路

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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值