P 算法与 K 算法
P 算法与 K 算法
作者:Grey
原文地址:
说明
P 算法和 K 算法主要用来解决最小生成树问题,即:不破坏连通性删掉某些边,使得整体的权重最小。
测评链接:牛客-最小生成树
K 算法
K 算法使用的核心数据结构是并查集,然后将边权值排序。
1)总是从权值最小的边开始考虑,依次考察权值依次变大的边
2)当前的边要么进入最小生成树的集合,要么丢弃
3)如果当前的边进入最小生成树的集合中不会形成环,就要当前边
4)如果当前的边进入最小生成树的集合中会形成环,就不要当前边
5)考察完所有边之后,最小生成树的集合也得到了
边存在小根堆里面,保证每次弹出的都是权重最小的值
点存在并查集中,每次加入一个边,就把两个边的点 union
完整代码如下
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] graph = new int[m][3];
for (int i = 0; i < m; i++) {
// from
graph[i][0] = in.nextInt();
// to
graph[i][1] = in.nextInt();
// weight
graph[i][2] = in.nextInt();
}
System.out.println(k(graph, n));
in.close();
}
// k算法生成最小生成树
public static int k(int[][] graph, int n) {
UnionFind uf = new UnionFind(n);
Arrays.sort(graph, Comparator.comparingInt(o -> o[2]));
int ans = 0;
for (int[] edge : graph) {
if (!uf.same(edge[0], edge[1])) {
uf.union(edge[0], edge[1]);
ans += edge[2];
}
}
return ans;
}
public static class UnionFind {
private final int[] parent;
private final int[] size;
private final int[] help;
public UnionFind(int n) {
parent = new int[n + 1];
size = new int[n + 1];
help = new int[n + 1];
for (int i = 1; i < n; i++) {
parent[i] = i;
size[i] = 1;
}
}
public boolean same(int a, int b) {
return find(a) == find(b);
}
private int find(int a) {
int index = 0;
while (a != parent[a]) {
help[index++] = a;
a = parent[a];
}
index--;
while (index > 0) {
parent[help[index--]] = a;
}
return a;
}
public void union(int a, int b) {
int f1 = find(a);
int f2 = find(b);
if (f1 != f2) {
int size1 = size[f1];
int size2 = size[f2];
if (size1 > size2) {
parent[f2] = f1;
size[f2] = 0;
size[f1] = size1 + size2;
} else {
parent[f1] = f2;
size[f1] = 0;
size[f2] = size1 + size2;
}
}
}
}
}
P 算法
1)可以从任意节点出发来寻找最小生成树
2)某个点加入到被选取的点中后,解锁这个点出发的所有新的边
3)在所有解锁的边中选最小的边,然后看看这个边会不会形成环
4)如果会,不要当前边,继续考察剩下解锁的边中最小的边,重复3)
5)如果不会,要当前边,将该边的指向点加入到被选取的点中,重复2)
6)当所有点都被选取,最小生成树就得到了
完整代码如下
import java.util.*;
public class Main {
public static Set<Edge> P(Graph graph) {
// 解锁的边进入小根堆
PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(o -> o.weight));
// 哪些点被解锁出来了
HashSet<Node> nodeSet = new HashSet<>();
Set<Edge> result = new HashSet<>(); // 依次挑选的的边在result里
for (Node node : graph.nodes.values()) { // 随便挑了一个点
// node 是开始点
if (!nodeSet.contains(node)) {
nodeSet.add(node);
for (Edge edge : node.edges) { // 由一个点,解锁所有相连的边
priorityQueue.add(edge);
}
while (!priorityQueue.isEmpty()) {
Edge edge = priorityQueue.poll(); // 弹出解锁的边中,最小的边
Node toNode = edge.to; // 可能的一个新的点
if (!nodeSet.contains(toNode)) { // 不含有的时候,就是新的点
nodeSet.add(toNode);
result.add(edge);
for (Edge nextEdge : toNode.edges) {
priorityQueue.add(nextEdge);
}
}
}
}
// 如果有森林,就不能break,如果没有森林,就可以break
//break;
}
return result;
}
public static class Graph {
public HashMap<Integer, Node> nodes;
public HashSet<Edge> edges;
public Graph(int n) {
nodes = new HashMap<>();
edges = new HashSet<>(n);
}
}
public static class Node {
public int value;
public int in;
public int out;
public ArrayList<Node> nexts;
public ArrayList<Edge> edges;
public Node(int value) {
this.value = value;
in = 0;
out = 0;
nexts = new ArrayList<>();
edges = new ArrayList<>();
}
}
public static class Edge {
public int weight;
public Node from;
public Node to;
public Edge(int weight, Node from, Node to) {
this.weight = weight;
this.from = from;
this.to = to;
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
Graph graph = new Graph(n);
for (int i = 0; i < m; i++) {
int from = in.nextInt();
int to = in.nextInt();
int weight = in.nextInt();
if (!graph.nodes.containsKey(from)) {
graph.nodes.put(from, new Node(from));
}
if (!graph.nodes.containsKey(to)) {
graph.nodes.put(to, new Node(to));
}
Node fromNode = graph.nodes.get(from);
Node toNode = graph.nodes.get(to);
Edge fromToEdge = new Edge(weight, fromNode, toNode);
Edge toFromEdge = new Edge(weight, toNode, fromNode);
fromNode.nexts.add(toNode);
fromNode.out++;
fromNode.in++;
toNode.out++;
toNode.in++;
fromNode.edges.add(fromToEdge);
toNode.edges.add(toFromEdge);
graph.edges.add(fromToEdge);
graph.edges.add(toFromEdge);
}
Set<Edge> result = P(graph);
int sum = 0;
for (Edge edge : result) {
sum += edge.weight;
}
System.out.println(sum);
in.close();
}
}
更多
参考资料
P 算法与 K 算法的更多相关文章
- 基于改进人工蜂群算法的K均值聚类算法(附MATLAB版源代码)
其实一直以来也没有准备在园子里发这样的文章,相对来说,算法改进放在园子里还是会稍稍显得格格不入.但是最近邮箱收到的几封邮件让我觉得有必要通过我的博客把过去做过的东西分享出去更给更多需要的人.从论文刊登 ...
- 算法训练 K好数
算法训练 K好数 时间限制:1.0s 内存限制:256.0MB 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数 ...
- [机器学习系列] k-近邻算法(K–nearest neighbors)
C++ with Machine Learning -K–nearest neighbors 我本想写C++与人工智能,但是转念一想,人工智能范围太大了,我根本介绍不完也没能力介绍完,所以还是取了他的 ...
- 程序员编程艺术:第三章续、Top K算法问题的实现
程序员编程艺术:第三章续.Top K算法问题的实现 作者:July,zhouzhenren,yansha. 致谢:微软100题实现组,狂想曲创作组. 时间:2011年05月08日 ...
- 机器学习——KNN算法(k近邻算法)
一 KNN算法 1. KNN算法简介 KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分 ...
- 算法训练 K好数 解析
算法训练 K好数 时间限制:1.0s 内存限制:256.0MB 提交此题 锦囊1 锦囊2 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K ...
- 强连通分量【k 算法、t 算法】
连通分量就是一个各个顶点能互相达到的图 无向图的连通分量选取任意一个顶点使用DFS遍历即可,遍历完所有顶点所需的DFS的次数就是连通分量的数量 有向图的强连通分量由于是有向的[从A点开始DFS能访问到 ...
- Top K算法
应用场景: 搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节. 假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果 ...
- 【十大经典数据挖掘算法】k
[十大经典数据挖掘算法]系列 C4.5 K-Means SVM Apriori EM PageRank AdaBoost kNN Naïve Bayes CART 1. 引言 k-means与kNN虽 ...
随机推荐
- BMP位图之4位位图(二)
起始结构 typedef struct tagBITMAPFILEHEADER { WORD bfType; //类型名,字符串"BM", DWORD bfSize; //文件大小 ...
- 关于mybatis-plus出现Not Found TableInfoCache. 的解决方法
查看自己的pom里面是不是导入了多个mybatis相关,若是的话就全部删去,然后添加如下代码段即可 <dependency> <groupId>com.baomidou< ...
- (防坑)Alphafold 非docker 安装指南
本指南适用于Linux系统.Alphafold官方也强调尽量使用Linux系统!官方提供了docker版安装步骤. Alphafold简介: 强大的蛋白质结构预测. 开源地址:https://gith ...
- 定语从句关系代词只能用 that 的情况
当先行词被形容词最高级.序数词,以及 the only.the very.the right 等修饰时,关系代词只能用 that. This is the most interesting movie ...
- 如何在 HTML 中调整图像大小?
了解在 HTML 中调整图像大小的不同技术.何时应避免在浏览器端调整大小,以及在 Web 上操作和提供图像的正确方法. 如果您的图像不适合布局,您可以在 HTML 中调整其大小.在 HTML 中调整图 ...
- linux 的文件权限案列
需求: 技术部门人员可以相互查看,但不能删除和修改别人的文件,其他部门人员不能查看,但领导组可以且只能查看. 设计: 技术部: 组 jishu ; 人员 js1, js2 领导:组 lingd ; 人 ...
- 【NOI P模拟赛】奶油蛋糕塔(状压 DP)
题面 数据范围 1 ≤ n ≤ 5 × 1 0 5 1\leq n\leq5\times10^5 1≤n≤5×105 . 题解 n ≤ 20 n\leq 20 n≤20 的状压应该都会吧,状态记录已经 ...
- gcd(数论)
题目描述 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对? 输入 一个整数 1<=N<=1000000 输出 一个整数 样例输入 4 样例输出 ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...
- K8s nginx-ingress 如何配置二级目录转发远程静态服务器基于Vue路由history模式打包的应用程序
背景 首先这标题有点绕,我先解释下: 首先我们有静态服务器,上面某个目录有Vue路由history模式打包的应用程序(也就是build后的产物): 但是静态服务器一般不做对外域名用的,我们需要在k8s ...