算法训练营第七十天
最小生成树之prim
题目链接:https://kamacoder.com/problempage.php?pid=1053
- 随意将一个节点放入set作为初始状态。每次从和set中节点相连的权值最小的边相连的节点放入并记录权值。直到set大小和节点数相同。
代码如下:
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
using namespace std;
int main() {
int m, n, s, t;
cin >> n >> m;
vector<int> inDegree(n, 0); // 记录每个文件的入度
unordered_map<int, vector<int>> umap;// 记录文件依赖关系
vector<int> result; // 记录结果
while (m--) {
// s->t,先有s才能有t
cin >> s >> t;
inDegree[t]++; // t的入度加一
umap[s].push_back(t); // 记录s指向哪些文件
}
queue<int> que;
for (int i = 0; i < n; i++) {
// 入度为0的文件,可以作为开头,先加入队列
if (inDegree[i] == 0) que.push(i);
//cout << inDegree[i] << endl;
}
// int count = 0;
while (que.size()) {
int cur = que.front(); // 当前选中的文件
que.pop();
//count++;
result.push_back(cur);
vector<int> files = umap[cur]; //获取该文件指向的文件
if (files.size()) { // cur有后续文件
for (int i = 0; i < files.size(); i++) {
inDegree[files[i]] --; // cur的指向的文件入度-1
if(inDegree[files[i]] == 0) que.push(files[i]);
}
}
}
if (result.size() == n) {
for (int i = 0; i < n - 1; i++) cout << result[i] << " ";
cout << result[n - 1];
} else cout << -1 << endl;
}
最小生成树之Kruskal
题目链接:https://kamacoder.com/problempage.php?pid=1191
- 用到了并查集,每次对两个节点不连通的情况进行处理,记录最小权值的边。之后对两个节点使用并查集中的join,直到没有不连通的节点
代码如下:
#include <iostream>
#include <vector>
using namespace std;
int father[10001];
void init() {
for (int i = 0; i <= 10000; i++) father[i] = i;
}
int find(int a) {
while (father[a] != a) {
a = father[a];
}
return a;
}
bool isSame(int a, int b) {
a = find(a);
b = find(b);
return a == b;
}
void join(int a, int b) {
if (isSame(a, b)) return;
father[find(a)] = b;
return;
}
int main() {
int v, e;
cin >> v >> e;
vector<vector<int>> edges(e, vector<int>(3, 0));
for (int i = 0; i < e; i++) {
for (int j = 0; j < 3; j++) {
cin >> edges[i][j];
}
}
int dis = 0;
init();
bool flag = true;
while (flag) {
flag = false;
int min = 10000;
int minIndex = -1;
for (int i = 0; i < e; i++) {
if (isSame(edges[i][0], edges[i][1])) continue;
flag = true;
if (min > edges[i][2]) {
min = edges[i][2];
minIndex = i;
}
}
if (flag == true) {
dis += min;
join(edges[minIndex][0], edges[minIndex][1]);
}
}
cout << dis << endl;
}
软件构建
- 这题之前一次笔试写过,当时最后一个元素后也加了空格,导致只过了30%,大家注意下
代码如下:
#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
queue<long int> my_resque;
queue<long int> my_midque;
map<long int, set<long int>> mymap;
map<long int, long int> nummap;
set<long int> res;
int flag = 0;
for (int i = 0; i < n; i++) nummap[i] = 0;
for (int i = 0; i < m; i++) {
long int a, b;
cin >> a >> b;
mymap[b].insert(a);
nummap[b]=mymap[b].size();
}
while (res.size() < n) {
int num = res.size();
for (int i = 0; i < n; i++) {
if (res.find(i) == res.end() && nummap[i] == 0) {
my_midque.push(i);
res.insert(i);
my_resque.push(i);
}
}
if (num == res.size() && num != n) break;
while (!my_midque.empty()) {
long int t = my_midque.front();
my_midque.pop();
for (int i = 0; i < n; i++) {
if (res.find(i) == res.end() &&
nummap[i] > 0 && mymap[i].find(t) != mymap[i].end())
nummap[i]--;
}
}
}
if (res.size() < n) cout << -1 << endl;
else {
while (!my_resque.empty())
{
if (my_resque.size() > 1)
cout << my_resque.front() << ' ';
else cout << my_resque.front();
my_resque.pop();
}
cout << endl;
}
return 0;
}