一、最小生成树
对应的图都为无向图
(1)朴素Prim算法
注意与Dijkstra算法(朴素版)的区别!!!
AcWing 858. Prim算法求最小生成树 - AcWing
import java.util.*;
public class Main{
static int N = 510, m, n, max = 0x3f3f3f3f;
static int[][] g = new int[N][N];
static int[] dist = new int[N];
static boolean[] st = new boolean[N];//最小生成树的点的集合
public static void prim(){
Arrays.fill(dist, max);
dist[1] = 0;
int res = 0;//最小生成树的路径之和
for(int i = 0; i < n; i ++){//循环n次,找到n个点
int t = -1;
for(int j = 1; j <= n; j ++){
if(!st[j] && (t == -1 || dist[t] > dist[j])){//t=-1表示这次循环还没找到数
t = j;
}
}
if(dist[t] == max){//说明是不连通的
System.out.print("impossible");
return;
}
res += dist[t];
st[t] = true;//将这个点放进集合中
for(int j = 1; j <= n; j ++){//这与dijkstra算法不一样,这是其他点到集合(集合里的任何一个点)的最短距离
if(!st[j]) dist[j] = Math.min(dist[j], g[t][j]);//dijkstra是其他点到起始点的距离
}
}
System.out.print(res);//返回最小生成树的路径和
return;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for(int i = 1; i <= n; i ++){
Arrays.fill(g[i], max);
}
while(m -- > 0){
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
g[a][b] = g[b][a] = Math.min(g[a][b], c);//稠密图用邻接矩阵来存储
}
prim();
}
}
(2)Kruskal算法
859. Kruskal算法求最小生成树 - AcWing题库
1.关于java中Arrays.sort()的几种用法-CSDN博客
import java.util.*;
class PIIs implements Comparable<PIIs>{//构造一个结构体
int a, b, c;
public PIIs(int a, int b, int c){
this.a = a;
this.b = b;
this.c = c;
}
public int compareTo(PIIs o){
return Integer.compare(c, o.c);
}
}
public class Main{
static int N = 100010, M = 2 * N, n, m;
static int[] p = new int[N];
static PIIs[] q = new PIIs[M];
public static int find(int x){//并查集的基本操作
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
public static void kruskal(){
Arrays.sort(q, 0, m);//把所有的边按照权重的大小排序
int res = 0;//最小生成树的权重之和
int cnt = 0;//边数之和
for(int i = 0; i < m; i ++){//枚举所有的边
int a = q[i].a;
int b = q[i].b;
int c = q[i].c;
a = find(a);//判断a和b是否在同一个和当中
b = find(b);
if(a != b){//如果不在则执行以下操作
p[a] = b;//将点a与点b相连
res += c;//权重加上c
cnt ++;//边数加1
}
}
if(cnt < n - 1)//因为一共有n个点,所以要有n-1条边,如果小于,说明存在不连通的边
System.out.print("impossible");
else
System.out.print(res);//否则返回权重之和
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for(int i = 1; i <= n; i ++){//并查集的基本操作
p[i] = i;
}
for(int i = 0; i < m; i ++){
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
q[i] = new PIIs(a, b, c);
}
kruskal();
}
}
二、二分图
二分图当且仅当图中不含有奇数环
(1)染色法
由于图中不含有奇数环,所以染色过程一定没有矛盾
import java.util.*;
public class Main{
static int N = 100010, M = 200010, n, m, idx;
static int[] h = new int[N];
static int[] e = new int[M];
static int[] ne = new int[M];
static int[] color = new int[N];//初始化为0,也就是没有被染色
//邻接表存储
public static void add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
public static boolean dfs(int u, int c){
color[u] = c;//染上颜色1
for(int i = h[u]; i != -1; i = ne[i]){
int j = e[i];
if(color[j] == 0){
if(!dfs(j, 3 - c)) return false;//u的邻接点染上3-c,即颜色2或颜色1,根据u的颜色而定
}else{
if(color[j] == c) return false;//染色过程出现矛盾,返回false
}
}
return true;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
Arrays.fill(h, -1);
while(m -- > 0){
int a = sc.nextInt();
int b = sc.nextInt();
add(a, b);
add(b, a);
}
boolean flag = true;
for(int i = 1; i <= n; i ++){
if(color[i] == 0){
if(!dfs(i, 1)){//没有被染色,就染上颜色1
flag = false;
break;
}
}
}
if(flag) System.out.print("Yes");
else System.out.print("No");
}
}
(2)匈牙利算法
import java.util.*;
public class Main{
static int N = 510, M = 100010, n1, n2, m, idx;
static int[] h = new int[N];
static int[] e = new int[M];
static int[] ne = new int[M];
static int[] match = new int[N];//match[i]表示的是i的男朋友是谁
static boolean[] st = new boolean[N];//标记这个姑娘在一轮中的状态。一轮指的是每个男生找对象的一轮
//邻接表存储
public static void add(int a, int b){
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
public static boolean find(int u){
//遍历这个男生所有有好感的女生
for(int i = h[u]; i != -1; i = ne[i]){
int j = e[i];//把这个女生拿出来
if(!st[j]){//判断在这一轮中是否被选过
st[j] = true;//标记为选过
if(match[j] == 0 || find(match[j])){//如果这个女生没有男朋友或者她男朋友还可以有另一个选择
match[j] = u;//那么就把这个女生给这个男生
return true;
}
}
}
return false;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n1 = sc.nextInt();
n2 = sc.nextInt();
m = sc.nextInt();
Arrays.fill(h, -1);
while(m -- > 0){
int a = sc.nextInt();
int b = sc.nextInt();
add(a, b);
}
int res = 0;//记录匹配的数量
for(int i = 1; i <= n1; i ++){
Arrays.fill(st, false);//清空st,表示在这一轮中所有女生都没有被选过
if(find(i)){
res ++;//如果这个男生成功匹配,那么匹配数量加1
}
}
System.out.print(res);
}
}