基础算法三 - 搜索与图论

本文详细介绍了图论的基础知识,包括DFS和BFS搜索、最短路径算法如Dijkstra、Bellman-Ford和Floyd,最小生成树的Prim和Kruskal算法,以及二分图的染色法和匈牙利算法。通过实例解析了如何判断负环和求解最大匹配问题。
摘要由CSDN通过智能技术生成

本文包括4大部分,图基础、最短路径、最小生成树、二分图
一、图基础包含, DFS、BFS、拓扑排序
二、最短路径包含,1.朴素Dijkstra, 2.堆优化Dijksta, 3.Bellman-ford,4.SPFA最短路径,5.SPFA判断负环, 6. Floyd最短路径
在这里插入图片描述
三、最小生成树包含,1. Prim, 2.Kruskal
在这里插入图片描述
四、1.染色法判定二分图,2.匈牙利算法
在这里插入图片描述

一、图基础

DFS和BFS均用邻接表来访问, vi数组记录已访问节点
拓扑排序不需要vi数组记录, 基于inDgree数组来记录入度值, 为0则入自定义队列q来进行BFS, 如果tt + 1 == n,证明入队了n个节点, 完成排序,否则存在环

1.DFS 题目: 树的重心

import java.io.*;
import java.util.*;
/**
 * 图的临接表遍历
 * 1.定义临接表adj, 访问数组vi
 * 2.dfs遍历输入当前节点dfs(node), for循环node为头的单链表节点j
 * 如果j未被访问,则dfs(j)
 */
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 100010, idx, n;//二叉树n个节点
    static int[] e = new int[N * 2], ne = new int[N * 2], adj = new int[N]; //临接表
    static int ans = 0x3f3f3f3f;
    static boolean[] vi = new boolean[N];
    public static int dfs(int node){
        vi[node] = true;
        int sum = 1, res = 0;
        for(int i = adj[node]; i != -1; i = ne[i]){
            int next = e[i];
            if(!vi[next]){
                int size = dfs(next);
                res = Math.max(size, res);
                sum += size;
            }
        }
        res = Math.max(res, n - sum); //求以node节点为删除节点后,各个连通块的最大值
        ans = Math.min(ans, res);
        return sum;
    }
    public static void main(String[] args) throws Exception{
        n = Integer.valueOf(read.readLine());
        Arrays.fill(adj, -1);
        for(int i = 1; i < n; i++){
            String[] s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            add(a, b); add(b, a);//构建临接表
        }
        dfs(1);
        System.out.println(ans);
    }
    public static void add(int a, int b){
        e[idx] = b; ne[idx] = adj[a]; adj[a] = idx++;
    }
}

2.BFS 图的层次遍历

import java.io.*;
import java.util.*;
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 100010, idx = 0, n, m;
    static int[] e = new int[N * 2], ne = new int[N * 2], adj = new int[N];//邻接表
    static int[] dist = new int[N];
    static boolean[] vi = new boolean[N];
    public static void add(int a, int b){
        e[idx] = b; ne[idx] = adj[a]; adj[a] = idx++;
    }
    public static int bfs(){
        Queue<Integer> q = new LinkedList();
        q.offer(1);
        Arrays.fill(dist, 0x3f3f3f3f);
        dist[1] = 0;
        while(!q.isEmpty()){
            int poll = q.poll();
            vi[poll] = true;
            for(int i = adj[poll]; i != -1; i = ne[i]){
                int next = e[i];
                if(!vi[next]){
                    q.offer(next);
                    dist[next] = Math.min(dist[next], dist[poll] + 1);
                }
            }
        }
        if(dist[n] == 0x3f3f3f3f)   return -1;
        return dist[n];
    }
    
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]); m = Integer.valueOf(s[1]);
        Arrays.fill(adj, -1);
        while(m -- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            add(a, b);
        }
        System.out.println(bfs());
    }
}

3.有向图的拓扑序列 有向图的拓扑序列

import java.util.*;
import java.io.*;
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 100010, idx = 0, n, m;
    static int[] e = new int[N * 2], ne = new int[N * 2], adj = new int[N];
    static int[] q = new int[N];
    static int[] inDegree = new int[N];
    public static boolean tpsort(){
        int hh = 0, tt = -1;
        for(int i = 1; i <= n; i++){
            if(inDegree[i] == 0)    q[++tt] = i;
        }
        while(hh <= tt){
            int poll = q[hh++];
            for(int i = adj[poll]; i != -1; i = ne[i]){
                int next = e[i];
                inDegree[next]--;
                if(inDegree[next] == 0) q[++tt] = next;
            }
        }
        return tt + 1 == n;
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        m = Integer.valueOf(s[1]);
        Arrays.fill(adj, -1);
        while(m -- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            add(a, b);
            inDegree[b]++;
        }
        if(!tpsort()){
            System.out.println("-1");
        }else{
            for(int i = 0; i < n; i++){
                System.out.print(q[i] + " ");
            }
        }
    }
    public static void add(int a, int b){
        e[idx] = b; ne[idx] = adj[a]; adj[a] = idx++;
    }
}

二、最短路径

1.朴素Dijkstra

import java.util.*;
import java.io.*;
/**
 * 算法: 贪心思想
 * 1. 初始化距离为无穷大, 临接矩阵也初始化为无穷大
 * 2. 找到距离最小的点,从该点出发更新到其他点的距离
 * 重复1. 2
 * 时间复杂度O(n ^ 2)
 */
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 510;
    static int[][] g = new int[N][N];
    static int[] dis = new int[N];
    static boolean[] vi  = new boolean[N];
    static int n, INF = 0x3f3f3f3f;
    public static int dijkstra(){
        Arrays.fill(dis, INF);
        dis[1] = 0;
        for(int i = 0; i < n; i++){
            int minDisNode = -1;
            for(int j = 1; j <= n; j++){
                if(!vi[j] && (minDisNode == -1 || dis[j] < dis[minDisNode])){
                    minDisNode = j;
                }
            }
            vi[minDisNode] = true;
            for(int j = 1; j <= n; j++){
                dis[j] = Math.min(dis[j], dis[minDisNode] + g[minDisNode][j]);
            }
        }
        if(dis[n] == INF) return -1;
        return dis[n];
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        for(int i = 1;i <= n; i++) Arrays.fill(g[i], INF);
        int m = Integer.valueOf(s[1]);
        while(m -- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int w = Integer.valueOf(s[2]);
            g[a][b] = Math.min(g[a][b], w);
        }
        System.out.println(dijkstra());
    }
}

2.堆优化Dijksta

import java.io.*;
import java.util.*;
/**
 * 算法思路: 贪心
 * 1. 稀疏图用临接表
 * 2. 维护一个小根堆,存放dist距离和节点node
 * 3. 进入未确定最小距离的节点, 遍历临接表,往小根堆里放距离更新的new int[]{dist, node}
 * 4. 重复循环步骤3
 */
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 1000010;
    static int[] e, ne, w, adj, dist; //临接表可以忽略重边和自环问题
    static int idx = 0, n, INF = 0x3f3f3f3f;
    static boolean[] vi;
    public static void add(int a, int b, int c){
        e[idx] = b; w[idx] = c; ne[idx] = adj[a]; adj[a] = idx++;
    }
    
    public static int dijkstra(){
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
        Arrays.fill(dist, INF);
        pq.offer(new int[]{0,1});
        while(!pq.isEmpty()){
            int[] poll = pq.poll();
            int distance = poll[0];
            int node = poll[1];
            if(vi[node]) continue;
            vi[node] = true;
            for(int i = adj[node]; i != -1; i = ne[i]){
                int j = e[i];
                if(dist[j] > distance + w[i]){
                    dist[j] = distance + w[i];
                    pq.offer(new int[]{dist[j], j});
                }
            }
        }
        if(dist[n] == INF)  return -1;
        return dist[n];
    }
    
    public static void main(String[] args) throws Exception{
        e = new int[N]; ne = new int[N]; w = new int[N]; adj = new int[N];
        dist = new int[N]; vi = new boolean[N];
        String[] s = read.readLine().split(" ");
        Arrays.fill(adj, -1);
        n = Integer.valueOf(s[0]); int m = Integer.valueOf(s[1]);
        while(m -- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int c = Integer.valueOf(s[2]);
            add(a, b, c);
        }
        System.out.println(dijkstra());
    }
    
}

3. Bellman-ford

import java.io.*;
import java.util.*;
class Main{
    static class Edge{
        int a, b, w;
        Edge(int a, int b, int w){
            this.a = a; this.b = b; this.w = w;
        }
    }
    static int n, m, k;
    static int M = 100010, N = 510, INF = 0x3f3f3f3f;
    static Edge[] edges = new Edge[M];
    static int[] dist = new int[N];
    static int[] backup = new int[N];
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    public static int bellmanFord(){
        Arrays.fill(dist, INF);
        dist[1] = 0;
        for(int i = 0; i < k; i++){
            backup = dist.clone();
            for(int j = 0; j < m; j++){
                int a = edges[j].a;
                int b = edges[j].b;
                int w = edges[j].w;
                dist[b] = Math.min(dist[b], backup[a] + w);
            }
        }
        if(dist[n] > INF / 2)   return -1;
        return dist[n];
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]); m = Integer.valueOf(s[1]);
        k = Integer.valueOf(s[2]);
        for(int i = 0; i < m; i++){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int w = Integer.valueOf(s[2]);
            edges[i] = new Edge(a, b, w);
        }
        int t = bellmanFord();
        if(t == -1) System.out.println("impossible");
        else System.out.println(t);
    }
}

4.SPFA最短路径

import java.util.*;
import java.io.*;
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 100010;
    static int[] e = new int[N], ne = new int[N], w = new int[N], adj = new int[N];
    static int n, m, INF = 0x3f3f3f3f, idx = 0;
    static boolean[] vi = new boolean[N];
    static int[] dist = new int[N];
    public static void add(int a, int b, int c){
        e[idx] = b; w[idx] = c; ne[idx] = adj[a]; adj[a] = idx++;
    }
    public static int spfa(){
        Arrays.fill(dist, INF);
        dist[1] = 0;
        Queue<Integer> q = new LinkedList();
        q.offer(1);
        while(!q.isEmpty()){
            int poll = q.poll();
            vi[poll] = false;
            for(int i = adj[poll]; i != -1; i = ne[i]){
                int next = e[i];
                if(dist[next] > dist[poll] + w[i]){
                    dist[next] = dist[poll] + w[i];
                    if(!vi[next]){
                        q.offer(next);
                        vi[next] = true;
                    }
                }
            }
        }
        if(dist[n] == INF)  return -1;
        return dist[n];
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        m = Integer.valueOf(s[1]);
        Arrays.fill(adj, -1);
        while(m-- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int c = Integer.valueOf(s[2]);
            add(a, b, c);
        }
        int tmp = spfa();
        if(tmp == -1){
            System.out.println("impossible");
        }else{
            System.out.println(tmp);
        }
    }
}

5.SPFA判断负环

算法分析
使用spfa算法解决是否存在负环问题

1、dist[x] 记录当前1到x的最短距离
2、cnt[x] 记录当前最短路的边数,初始每个点到1号点的距离为0,只要他能再走n步,即cnt[x] >= n,则表示该图中一定存在负环,由于从1到x至少经过n条边时,则说明图中至少有n + 1个点,表示一定有点是重复使用
3、若dist[j] > dist[t] + w[i],则表示从t点走到j点能够让权值变少,因此进行对该点j进行更新,并且对应cnt[j] = cnt[t] + 1,往前走一步
注意:该题是判断是否存在负环,并非判断是否存在从1开始的负环,因此需要将所有的点都加入队列中,更新周围的点

import java.io.*;
import java.util.*;
class Main{
    static int N = 10010;
    static int[] e = new int[N], ne = new int[N], adj = new int[N], w = new int[N];
    static int n, m , idx = 0, INF = 0x3f3f3f3f;
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static boolean[] vi = new boolean[N];
    static int[] dist = new int[N];
    static int[] cnt = new int[N];
    public static boolean spfa(){
        Arrays.fill(dist, INF);
        Queue<Integer> q = new LinkedList();
        for(int i = 1; i <= n; i++){
            q.offer(i);  vi[i] = true;
        }
        while(!q.isEmpty()){
            int poll = q.poll();
            vi[poll] = false;
            for(int i = adj[poll]; i != -1; i = ne[i]){
                int next = e[i];
                if(dist[next] > dist[poll] + w[i]){
                    cnt[next] = cnt[poll] + 1;
                    if(cnt[next] >= n)  return true;
                    dist[next] = dist[poll] + w[i];
                    if(!vi[next]){
                        q.offer(next);
                        vi[next] = true;
                    }
                }
            }
        }
        return false;
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        m = Integer.valueOf(s[1]);
        Arrays.fill(adj, -1);
        while(m -- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int c = Integer.valueOf(s[2]);
            add(a, b, c);
        }
        if(spfa()){
            System.out.println("Yes");
        }else{
            System.out.println("No");
        }
        
    }
    public static void add(int a, int b, int c){
        e[idx] = b; w[idx] = c; ne[idx] = adj[a]; adj[a] = idx++;
    }
}

6. Floyd最短路径

import java.io.*;
import java.util.*;
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int n, m, k, N = 210;
    static int[][] g = new int[N][N];
    static int INF = 0x3f3f3f3f;
    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++){
                    g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]);
                }
            }
        }
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        m = Integer.valueOf(s[1]);
        k = Integer.valueOf(s[2]);
        //初始化临接矩阵
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                if(i == j)  g[i][j] = 0;
                else g[i][j] = INF;
            }
        }
        while(m-- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int c = Integer.valueOf(s[2]);
            g[a][b] = Math.min(g[a][b], c);
        }
        floyd();
        while(k-- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            if(g[a][b] > INF/2) System.out.println("impossible");
            else System.out.println(g[a][b]);
        }
    }
}

三、最小生成树

1. Prim

/*
S:当前已经在联通块中的所有点的集合
1. dist[i] = inf
2. for n 次
    t<-S外离S最近的点
    利用t更新S外点到S的距离
    vi[t] = true
n次迭代之后所有点都已加入到S中
联系:Dijkstra算法是更新到起始点的距离,Prim是更新到集合S的距离
*/
import java.io.*;
import java.util.*;
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 510, M = 200010, INF = 0x3f3f3f3f;
    static int[][] g = new int[N][N];
    static int n, m;
    static int[] dist = new int[N];
    static boolean[] vi = new boolean[N];
    public static int prim(){
        Arrays.fill(dist, INF);
        int res = 0;
        for(int i = 0; i < n; i++){
            int node = -1;
            for(int j = 1; j <= n; j++){
                if(!vi[j] && (node == -1 || dist[node] > dist[j])){
                    node = j;
                }
            }
            vi[node] = true;
            //寻找离集合S最近的点, 如果距离是无穷大,证明不连通
            if(i != 0 && dist[node] == INF) return INF;
            //距离必须要先加,再更新,因为可能存在自环的情况
            if(i != 0)  res += dist[node];
            for(int j = 1; j <= n; j++){
                dist[j] = Math.min(dist[j], g[node][j]);
            }
        }
        return res;
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]); m = Integer.valueOf(s[1]);
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                if(i == j) g[i][j] = 0;
                else g[i][j] = INF;
            }
        }
        while(m-- > 0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int c = Integer.valueOf(s[2]);
            g[a][b] = g[b][a] = Math.min(g[a][b], c);
        }
        int t = prim();
        if(t == INF) System.out.println("impossible");
        else System.out.println(t);
    }
}

2.Kruskal

/**
 *  O(mlogm) m 为边数
 * 1.将所有边按权重从小到大排序
 * 2.枚举每条边a,b 权重c 
 *   if  a,b 两点不连通
 *       将a,b边加入集合中
 * 
 * 注意:(1) 2操作是并查集操作
 *       (2) 需要使用变量cnt来记录加进集合的边数
 *               若cnt < n - 1表示不能遍历所有点
 */
import java.util.*;
import java.io.*;
class Main{
    static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
    static int N = 100010, M = 200010, INF = 0x3f3f3f3f;
    static int n, m, idx = 0;
    static int[] father = new int[N];
    
    public static int kruskal(int[][] edges){
        Arrays.sort(edges, (o1,o2) -> o1[2] - o2[2]);
        int cnt = 0, res = 0;
        for(int i = 0; i < m; i++){
            int a = edges[i][0]; int b = edges[i][1];
            if(find(a) != find(b)){
                union(a, b);
                res += edges[i][2];
                cnt ++;
            }
        }
        if(cnt < n - 1) return INF;
        return res;
    }
    public static int find(int n){
        if(father[n] != n) father[n] = find(father[n]);
        return father[n];
    }
    public static void union(int n1, int n2){
        int f1 = find(n1);  int f2 = find(n2);
        if(f1 == f2)    return;
        father[f1] = f2;
    }
    public static void main(String[] args) throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]); m = Integer.valueOf(s[1]);
        int[][] edges = new int[m][3];
        for(int i = 0; i < N; i++) father[i] = i;
        for(int i = 0; i < m; i++){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            int c = Integer.valueOf(s[2]);
            
            edges[i][0] = a; edges[i][1] = b; edges[i][2] = c;
        }
        int tmp = kruskal(edges);
        if(tmp == INF) System.out.println("impossible");
        else System.out.println(tmp);
    }
}

四、二分图

1.染色法判定二分图

/**
 * 染色法
 *      将所有点分成两个集合,使得所有边只出现在集合之间,就是二分图
 *      二分图:一定不含有奇数环, 不一定是连通图
 *  dfs版本
 *      代码思路:
 *      染色可以使用1和2区分不同颜色,用0表示未染色
 *      遍历所有点,每次将未染色的点进行dfs, 默认染成1或者2
 *      由于某个点染色成功不代表整个图就是二分图,因此只有某个点染色失败才能立刻break/return
 *      染色失败相当于至少存在2个点染了相同的颜色
 */ 
 
 import java.io.*;
 import java.util.*;
 class Main{
     static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
     static int N = 200010, n, m, idx;
     static int[] e = new int[N], ne = new int[N], adj = new int[N];
     static int[] vi = new int[N];
     public static boolean dfs(int curNode, int color){
         vi[curNode] = color;
         for(int i = adj[curNode]; i != -1; i = ne[i]){
             int nextNode = e[i];
             if(vi[nextNode] == 0) {
                 if(!dfs(nextNode, 3 - color)) return false;
             }else if(vi[nextNode] == color)    return false;
         }
         return true;
     }
     public static void main(String[] args)throws Exception{
        String[] s = read.readLine().split(" ");
        n = Integer.valueOf(s[0]);
        m = Integer.valueOf(s[1]);
        Arrays.fill(adj, -1);
        while(m-- >0){
            s = read.readLine().split(" ");
            int a = Integer.valueOf(s[0]);
            int b = Integer.valueOf(s[1]);
            add(a, b); add(b, a);
        }
        boolean flag = true;
        for(int i = 1; i <= n; i++){
            if(vi[i] == 0){
                boolean rs = dfs(i, 1);
                if(!rs) {
                    flag = false;
                    break;
                }
            }
        }
        if(flag) System.out.println("Yes");
        else System.out.println("No");
     }
     public static void add(int a, int b){
         e[idx] = b; ne[idx] = adj[a]; adj[a] = idx++;
     }
 }

2.匈牙利算法

    要了解匈牙利算法必须先理解下面的概念:
          匹配:在图论中,一个「匹配」是一个边的集合,其中任意两条边都没有公共顶点。
          最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。


    下面是一些补充概念:
          完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。
          交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
          增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替 路称为增广路(agumenting path)。

 import java.io.*;
 import java.util.*;
 class Main{
     static BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
     static int N = 510, M = 200050;
     static int[] e = new int[M], ne = new int[M], adj = new int[N];
     static int idx = 0;
     //vi[]数组我称为临时预定数组,vi[j]=a表示一轮模拟匹配中,女孩j被男孩a预定了。
     static boolean[] vi = new boolean[N];
     //match[j]=a,表示女孩j的现有配对男友是a
     static int[] match = new int[N];
     public static boolean find(int leftNode){
         for(int i = adj[leftNode]; i != -1; i = ne[i]){
             int rightNode = e[i];
             if(!vi[rightNode]){ //右边点未被预定
                vi[rightNode] = true;
                //如果右边女孩没有男朋友,或者她原来的男朋友能够预定其他喜欢的女孩,匹配成功。
                if(match[rightNode] == 0 || find(match[rightNode])){
                    match[rightNode] = leftNode;
                    return true;
                }
             }
         }
         //找不到右边能匹配的点
         return false;
     }
     public static void main(String[] args) throws Exception{
         String[] s = read.readLine().split(" ");
         int n1 = Integer.valueOf(s[0]);
         int n2 = Integer.valueOf(s[1]);
         int  m = Integer.valueOf(s[2]);
         Arrays.fill(adj, -1);
         while(m-- > 0){
             s = read.readLine().split(" ");
             int a = Integer.valueOf(s[0]);
             int b = Integer.valueOf(s[1]);
             add(a, b);
         }
         int res = 0;
         for(int i = 1; i <= n1; i++){
             Arrays.fill(vi, false);
             if(find(i)) res++;
         }
         System.out.println(res);
     }
     public static void add(int a, int b){
         e[idx] = b; ne[idx] = adj[a]; adj[a] = idx++;
     }
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值