目录
一、最短路算法
稠密图:邻接矩阵存储
稀疏图:邻接表存储(链式前向星)
规定n为点数 m为边数
1.朴素版的Dijkstra算法(当m等于或者接近n^2时使用)
//狄杰斯特拉算法
public class Main {
static final int N=510;
static int n,m;
static int[][] g=new int[N][N];
static int[] dist=new int[N];
static boolean[] st=new boolean[N];
public static int Dijkstra() {
Arrays.fill(dist,0x3f3f3f3f);
dist[1]=0;
for(int i=0;i<n;i++) {
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
st[t]=true;
for(int j=1;j<=n;j++)
dist[j]=Math.min(dist[j],dist[t]+g[t][j]);
}
return dist[n]==0x3f3f3f3f?-1:dist[n];
}
}
2.堆优化版的Dijkstra算法(当m等于或接近n时使用)
//狄杰斯特拉算法
public class Main {
static int n,m;
static final int N=150010;
static int[] dist=new int[N];
static boolean[] st=new boolean[N];
static int[] h=new int[N],e=new int[N],ne=new int[N],w=new int[N];
//实现小根堆
static PriorityQueue<int[]> min=new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] o1,int[] o2) {
return o1[1]-o2[1];
}
});
public static int Dijkstra() {
Arrays.fill(dist,0x3f3f3f3f);
dist[1]=0;
min.offer(new int[] {1,dist[1]});
while(!min.isEmpty()) {
//出队
int[] cur=min.poll();
int ver=cur[0];
int distance=cur[1];
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]) {
int j=e[i];
if(dist[j]>distance+w[i]) {
dist[j]=distance+w[i];
min.offer(new int[] {j,dist[j]});
}
}
}
return dist[n]==0x3f3f3f3f?-1:dist[n];
}
}
3.Bellman-ford算法(有边数限制时使用)
//贝尔曼-福特算法
public class Main {
static final int N=510,M=10010;
static int n,m,k;
static pair11[] edge=new pair11[M];
static int[] backup=new int[N]; //备份数组
static int[] dist=new int[N];
public static int bellman_ford() {
Arrays.fill(dist,0x3f3f3f3f);
dist[1]=0;
//循环k次 即最多经过k条边的最短路径
for(int i=1;i<=k;i++) {
System.arraycopy(dist,1,backup,1,dist.length-1);
for(int j=1;j<=m;j++) {
int a=edge[j].x;
int b=edge[j].y;
int c=edge[j].z;
dist[b]=Math.min(dist[b],backup[a]+c);
}
}
return dist[n]>0x3f3f3f3f/2?0x3f3f3f3f:dist[n];
}
}
//存边
class pair11{
int x,y,z;
public pair11() {
}
public pair11(int a,int b,int c) {
x=a;y=b;z=c;
}
}
4.spfa算法(存在负权边且无边数限制时使用)
//spfa算法
//1.spfa算法求最短路
public class Main {
static int n,m,idx=1;
static final int N=100010;
static int[] h=new int[N],e=new int[N],ne=new int[N],w=new int[N];
static int[] dist=new int[N];
static boolean[] st=new boolean[N];
static Queue<Integer> q=new LinkedList<Integer>();
public static int spfa() {
Arrays.fill(dist,0x3f3f3f3f);
dist[1]=0;
q.offer(1);
st[1]=true;
while(!q.isEmpty()) {
int t=q.poll();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]) {
int j=e[i];
if(dist[j]>dist[t]+w[i]) {
dist[j]=dist[t]+w[i];
if(!st[j]) {
st[j]=true;
q.offer(j);
}
}
}
}
return dist[n];
}
}
//2.spfa算法来求是否存在负环
public class Main {
static int n,m;
static int N=2010,M=10010,idx=1;
static int[] dist=new int[N];
static int[] h=new int[N],e=new int[M],ne=new int[M],w=new int[M];
static boolean[] st=new boolean[N];
static int[] cnt=new int[N];
static Queue<Integer> q=new LinkedList<Integer>();
public static boolean spfa() {
for(int i=1;i<=n;i++) {
q.offer(i);
st[i]=true;
}
while(!q.isEmpty()) {
//出队
int t=q.poll();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]) {
int j=e[i];
if(dist[j]>dist[t]+w[i]) {
dist[j]=dist[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j]) {
st[j]=true;
q.offer(j);
}
}
}
}
return false;
}
}
5.floyd算法(多源汇最短路问题时使用)
//弗洛伊德算法
//运用动态规划思想
public class Main{
static int N=210;
static int[][] d=new int[N][N];
public static void floyd(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=Math.min(d[i][j],d[i][k]+d[k][j]);
}
}
二、最小生成树
稠密图一般用朴素版的prim算法
稀疏图一般用克鲁斯卡尔算法和堆优化版的prim算法,堆优化版的prim算法一般不使用(很少用)。
1.朴素版Prim算法(稠密图时使用)
import java.util.Scanner;
import java.util.Arrays;
public class Main {
static int N=510,M=(int)1e5+10;
static int INF=0x3f3f3f3f;
static int[] dist=new int[N];
static int[][] g=new int[N][N];
static boolean[] st=new boolean[N];
static int n,m;
public static int prim() {
Arrays.fill(dist,INF);
int res=0;
for(int i=1;i<=n;i++) {
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
if(i!=1&&dist[t]==INF) return INF;
if(i!=1) res+=dist[t];
for(int j=1;j<=n;j++)
dist[j]=Math.min(dist[j],g[t][j]);
st[t]=true;
}
return res;
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int u,v,w;
n=sc.nextInt();
m=sc.nextInt();
for(int i=1;i<=n;i++) {
Arrays.fill(g[i],INF);
}
while(m--!=0) {
u=sc.nextInt();
v=sc.nextInt();
w=sc.nextInt();
g[u][v]=g[v][u]=Math.min(g[u][v],w);
}
int t=prim();
System.out.println(t==INF?"impossible":t);
}
}
2.Kruskal算法(稀疏图使用)
import java.util.*;
public class Main{
static int N=100010,M=2*100010;
static int n,m;
static int[] f=new int[N];
static pair10[] edge=new pair10[M];
public static int find(int x) {
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
public static int kruskal() {
Arrays.sort(edge,1,m+1,new Comparator<pair10>(){
public int compare(pair10 o1,pair10 o2){
return o1.c-o2.c;
}
});
int res=0,cnt=0;
for(int i=1;i<=m;i++) {
int a=edge[i].a;
int b=edge[i].b;
int c=edge[i].c;
a=find(a);
b=find(b);
if(a!=b) {
f[a]=b;
res+=c;
cnt++;
}
}
return cnt<n-1?0x3f3f3f3f:res;
}
}
class pair10{
int a,b,c;
public pair10(int x,int y,int z){
a=x;
b=y;
c=z;
}
}
三、二分图
1.二分图定义
二分图:当且仅当图中不含有奇数环(环的边数为奇数)
二分图也称为二部图,是图论中的一种特殊模型,也是一种特殊的网路流,最大的特点在于,可以将图中的顶点划分为两个集合,且同一集合内的点没有直接关联。通俗点说,实际上就是二分图可以将顶点划分到两个集合当中,使得同一集合中的点之间没有边,边只存在于两个集合的点之间。
2.二分图判定—染色法
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N=(int)1e5+10,M=(int)2e5+10;
static int n,m,idx=1;
static int[] h=new int[N],color=new int[N];
static int[] e=new int[M],ne=new int[M];
public static void addedge(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;
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;
}else if(color[j]==c)
return false;
}
return true;
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
Arrays.fill(h,-1);
n=sc.nextInt();
m=sc.nextInt();
for(int i=1;i<=m;i++) {
int a=sc.nextInt();
int b=sc.nextInt();
addedge(a,b);
addedge(b,a);
}
boolean flag=true;
for(int i=1;i<=n;i++) {
if(color[i]==0) {
if(!dfs(i,1)) {
flag=false;
break;
}
}
}
System.out.println(flag==true?"Yes":"No");
}
}
3.二分图最大匹配—匈牙利算法
import java.util.Arrays;
import java.util.Scanner;
public class acw861 {
static int n1,n2,m,idx=1;
static int N=510,M=(int)1e5+10;
static int[] h=new int[N],match=new int[N];
static int[] e=new int[M],ne=new int[M];
static boolean[] st=new boolean[N];
public static void addedge(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);
for(int i=1;i<=m;i++) {
int a=sc.nextInt();
int b=sc.nextInt();
addedge(a,b);
}
int res=0;
for(int i=1;i<=n1;i++) {
Arrays.fill(st,false);
if(find(i))
res++;
}
System.out.println(res);
}
}