1.Floyd算法
基于动态规划
思想见最短路径模板+解析——(FLoyd算法)_floyd其时间复杂度的解释_coderyzh的博客-CSDN博客
题解
import java.util.*;
public class Main{
static int max=0x3f3f3f3f,N=210;
static int n,m,k;
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]);
}
}
}
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) d[i][j]=0;
else d[i][j]=max;
}
}
while(m-->0){
int x=sc.nextInt();
int y=sc.nextInt();
int z=sc.nextInt();
d[x][y]=Math.min(d[x][y],z);
}
floyd();
while(k-->0){
int a=sc.nextInt();
int b=sc.nextInt();
if(d[a][b]>max/2) System.out.println("impossible");
else System.out.println(d[a][b]);
}
}
}
2.Prim算法
朴素版Prim
算法思想;
1.初始化dist数组为最大值
2.遍历dist数组 for(int i=0;i<n;i++)
3.找到集合外距离最近的点并赋给t
4.用t来更新其他点到集合的距离
5.st[t]=true;
题解
import java.util.*;
public class Main{
static int n,m;
static int max=0x3f3f3f3f;
static int N=510;
static int[][] g=new int[N][N];
static int[] dist=new int[N];
static boolean[] st=new boolean[N];
public static int prim(){
Arrays.fill(dist,max);//dist数组初始化
dist[1]=0;
int res=0;//用于记录最小生成树的权重和
for(int i=0;i<n;i++){
int t=-1;//表示还没有找到
for(int j=1;j<=n;j++){
if(!st[j]&&(t==-1||dist[t]>dist[j]))
t=j;
}//找到集合外的点中离集合最近的点
if(dist[t]==max) return max;//表示点没有连通 说明不是连通图 不存在最小生成树
res+=dist[t];//连通图 加上集合外的点中离集合最近点到集合的最短距离
st[t]=true;//将该点加入集合
//用这个点去更新其他的点到集合的距离
for(int j=1;j<=n;j++){
if(!st[j])
dist[j]=Math.min(dist[j],g[t][j]);
}
}
return 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++)
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);
}
int t=prim();
if(t==max) System.out.println("impossible");
else System.out.println(t);
}
}
3.Kruskal算法
算法思想:
1.将所有边按权重从小到大排序
2.枚举每条边 a,b,权重c
如果a,b不连通,将其加入集合中
题目描述同上
题解
import java.util.*;
public class Main{
static int n,m;
static int N=200010;
static int[] p=new int[N];
static Pair[] list=new Pair[N];
//找祖宗结点
public static int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
public static void kruskal(){
//数组排序
Arrays.sort(list,0,m);
int res=0;//记录权重和
int cnt=0;//记录集合当中点的数量
for(int i=0;i<m;i++){
int a=list[i].a;
int b=list[i].b;
int w=list[i].w;
a=find(a);
b=find(b);
if(a!=b){//如果a和b不是一个祖宗结点 说明a和b不在一个连通块中 加入其中
p[a]=b;
res+=w;
cnt++;
}
}
//cnt<n-1说明存在点是不连通的 无最小生成树
if(cnt<n-1) System.out.println("impossible");
else System.out.println(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 w=sc.nextInt();
list[i]=new Pair(a,b,w);
}
kruskal();
}
}
class Pair implements Comparable<Pair>{
int a,b,w;
public Pair(int a,int b,int w){
this.a=a;
this.b=b;
this.w=w;
}
public int compareTo(Pair o){
return Integer.compare(w,o.w);
}
}
kruskal算法的时间复杂度主要是对权重排序时带来的mlogm
4.染色法判定二分图
二分图中不存在奇数结点的环
算法思想:
for(int i=1;i<=n;i++)
if i 未被染色
dfs(i,颜色);
题解
import java.util.*;
public class Main{
static int n,m,idx;
static int N=100010,M=200010;
static int[] e=new int[M];
static int[] ne=new int[M];
static int[] h=new int[N];
static int[] color=new int[N];//存储每个结点对应的颜色
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;//给第u个结点染颜色c
//遍历邻接表
for(int i=h[u];i!=-1;i=ne[i]){
int j=e[i];
if(color[j]==0){//如果结点j未被染色
//递归深搜j结点 染色3-c(颜色1和颜色2)
if(!dfs(j,3-c)) return false;
}//如果与u相邻结点j的颜色也是c则说明不是二分图
else if(color[j]==c) return 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){
//如果从第i个结点深度优先搜索染色不符合要求
if(!dfs(i,1)){
flag=false;
break;
}
}
}
if(flag) System.out.println("Yes");
else System.out.println("No");
}
}
5.匈牙利算法
题意描述见匈牙利算法(简单易懂)_一只大秀逗的博客-CSDN博客
题解
import java.util.*;
public class Main{
static int N=510,M=100010;
static int n1,n2,m,idx;
static int[] e=new int[M];
static int[] ne=new int[M];
static int[] h=new int[N];
static int[] match=new int[N];//匹配数组 用于记录每位男生匹配的女生下标
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 x){
//遍历所有与男生x有暧昧关系的女生
for(int i=h[x];i!=-1;i=ne[i]){
int j=e[i];
//如果女生没有对象
if(!st[j]){
st[j]=true;
//如果女生没有对象或者女生有对象 但是女生的对象可以放弃她选择其他女生
if(match[j]==0||find(match[j])){
//男生匹配成功
match[j]=x;
return true;
}
}
}
//否则匹配失败
return false;
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n1=sc.nextInt();
int n2=sc.nextInt();
int 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);//每一轮重置所有女生的单身状况 默认为无对象
if(find(i)) res++;//匹配成功
}
System.out.println(res);
}
}