Coincidencia de gráficos bipartitos-algoritmo húngaro

Que es coincidente

Coincidencia : en la teoría de grafos, una "coincidencia" es un conjunto de aristas, en el que dos aristas cualesquiera no tienen vértices comunes.
Coincidencia máxima : entre todas las coincidencias en un gráfico, la coincidencia con los bordes más coincidentes se denomina coincidencia máxima de este gráfico.

Coincidencia de un gráfico bipartito : Dado un gráfico bipartito G, en un subgráfico M de G, dos aristas cualesquiera del conjunto de aristas {E} de M no están unidas al mismo vértice, entonces se dice que M es una coincidencia.
Coincidencia máxima de un gráfico bipartito : un grupo de coincidencias que contiene la mayor cantidad de aristas entre todas las coincidencias se denomina coincidencia máxima de un gráfico bipartito, y el número de aristas es el número máximo de coincidencias.

Algoritmo de Hungría

El método de coloración anterior es juzgar si un gráfico es un gráfico bipartito; el
algoritmo húngaro es un algoritmo para encontrar la máxima coincidencia del gráfico bipartito basado en el gráfico bipartito.

El gráfico bipartito divide los vértices en dos conjuntos A y B. No hay bordes entre los conjuntos A y B, y hay bordes entre los puntos en A y B. (Hay un borde entre el punto x en A y algunos puntos en B, puede haber uno, puede haber muchos o puede que no haya) La
coincidencia máxima es elegir tantos bordes como sea posible, de modo que los puntos en A y los puntos en B Emparejamiento, y solo emparejamiento uno a uno, es decir, los emparejados no se pueden emparejar nuevamente, de modo que dos aristas cualesquiera no tienen vértices comunes.

Los gráficos bipartitos son generalmente gráficos no dirigidos, Emparejamiento bidireccional, cuando estamos tratando de emparejar, solo necesitamos emparejar de una dirección a la otra: las siguientes preguntas y códigos asumen que desde el conjunto A hasta la mitad del conjunto B se empareja . Por lo tanto, aunque es un grafo no dirigido, solo podemos almacenar las aristas de A-> B , pero no las aristas de B-> A, de modo que los vértices se puedan dividir automáticamente en dos conjuntos, y los números de los nodos en los dos conjuntos Todos pueden comenzar desde 1 .

Proceso de emparejamiento

Si la chica que buscas ya tiene novio,
puedes preguntarle a su novio
si tienes una llanta de refacción,
¿me la puedes dar? Si
puede dejarlo ir,
si no puede dejarlo , son amor verdadero.
Buscas tu próxima llanta de repuesto.

Suponga que hay una relación de coincidencia temporal a1 ---- b1, a2 ---- b2 en este momento, el vértice a1 en A tiene puntos que apuntan a b1, b2, a2 ​​solo tiene aristas que apuntan a b2 y a3 tiene apunta a b1, b3, etc. Para el borde de ……, tomamos la coincidencia del vértice a3 en A como ejemplo:

Suponiendo que hay una relación coincidente a1 ---- b1, a2 ---- b2 temporalmente, entonces a2 no puede tener un borde que apunte a b1, de lo contrario no se ajusta al núcleo del algoritmo húngaro 1.

El siguiente proceso de análisis:

Encuentra un objeto coincidente para a3. A3 primero encuentra b1 y encuentra que b1 ha sido coincidente, pero en este momento a3 no está buscando b3, pero le pide a b1 que encuentre su objeto coincidente a1, y vea si a1 puede encontrar otros puntos que coincidan. , En este momento volvamos al problema de encontrar un objeto coincidente para a1 , pero el objeto coincidente b1 está prohibido , por lo que a1 ya no puede encontrar b1, y luego ir a b2, b2 no está prohibido, puedes encontrarlo, pero b2 ya tiene un objeto coincidente a2, y luego pregunte si a2 puede cambiar un objeto coincidente. En este momento, se vuelve al problema de encontrar un objeto coincidente para a2 . Al mismo tiempo, los puntos b1 y b2 están prohibidos , porque el punto b1 es lo que quiere el punto a3, el punto b2 es lo que quiere el punto a1, y todo está pendiente ,Pero a2 no tiene opción de volver, En este momento a2 y b2 son amor verdadero, están permanentemente emparejados y bloqueados . Luego regrese y dígale a a1, b2 no es bueno, puede encontrar el siguiente, pero a1 tampoco tiene espacio para retirarse , por lo que a1 y b1 también son amor verdadero, permanentemente emparejados y bloqueados. Luego dígale a a3, b1 no es bueno, puede encontrar el siguiente, y luego a3 comienza a encontrar b3 ...

La coincidencia anterior puede coincidir con la matriz, se puede representar un estado prohibido st matriz, la matriz está bloqueada se puede representar con
match[j]=iun punto que representa el punto i j en el conjunto A y el conjunto B coincide temporalmente con los
st[j]=truevértices j temporalmente desactivado
vis[j]=truerepresenta match[i]=jla i Y j es amor verdadero. No pienses en el vértice j de los vértices que vienen después.

Suponga que a1 solo tiene bordes que apuntan a b1 y b2, a2 ​​solo tiene bordes que apuntan a b1, b2 y a3 tiene bordes que apuntan a b1, b2 y b3.
Primero seleccione a1, haga coincidir [a1] = b1;
luego seleccione a2, y encuentra que b1 está ocupado. Luego fuerza a1 a ceder. En este momento, igualar [a1] = b2; igualar [a2] = b1;
Luego a3 selecciona , b1 está ocupado, y luego a3 obliga a a2 a ceder . A2 no puede elegir b1, solo puede elegir b2, luego a2 Obligando a a1 a ceder. En este momento, a1 no puede elegir b1 y b2. A1 no tiene espacio para retirarse. A1 y b2 están bloqueados. Después de decirle el mensaje a a2 , a2 no tiene espacio para retirarse, y a2 y b1 están bloqueados.
Cuando a3 encuentra b2, dígale a a3 directamente, b2 está bloqueado, no se muestra, puede encontrar el siguiente.
A continuación, a3 encuentra b3, hay coincidencia [a3] = b3;

Otro ejemplo es ilustrar el núcleo del algoritmo húngaro:

  1. La primera coincidencia es temporal, y la segunda coincidencia es la más probable de obtener, porque la primera coincidencia debe coincidir en la medida de lo posible, a menos que la primera coincidenciaproducirHasta el punto en que no hay retirada.
  2. Este es un proceso recursivo . La coincidencia al final de la recursividad no se debe solo a que el vértice de esta coincidencia tiene un grado de 1, y solo un borde se extiende a otro conjunto . Este es solo uno de los casos. La situación general es este vértice He llegado al punto en que no puedo retroceder, no puedo dar más a otros ápices, y me dejo ir.

Descripción del Título

Dado un gráfico bipartito, la mitad izquierda del conjunto contiene n1 puntos ( numerados 1-n1 ), la mitad derecha del conjunto contiene n2 puntos ( numerados 1-n2 ) y el gráfico bipartito contiene un total de m bordes.

Los datos garantizan que los dos puntos finales de cualquier borde no pueden estar en la misma parte.

Encuentre el número máximo de coincidencias del gráfico bipartito.

Formato de entrada La
primera línea contiene tres números enteros n1, n2 y m.

En las siguientes m líneas, cada línea contiene dos números enteros u y v, lo que indica que hay un borde entre el punto u en la mitad izquierda del conjunto de puntos y el punto v en la mitad derecha del conjunto de puntos.

Formato de
salida Genera un número entero, que representa el número máximo de coincidencias del gráfico bipartito.

Rango de datos
1≤n1,
n2≤500,
1≤u≤n1,
1≤v≤n2 , 1≤m≤10 5

Muestra de entrada:

2 2 4
1 1
1 2
2 1
2 2

Salida de muestra:

2

Implementación de algoritmos

#include <iostream>
#include <cstring>

using namespace std;

#define read(x) scanf("%d",&x)
const int N=510,M=1e5+10;  //虽是无向图,但是存储单方向的边A->B即可,到时候从A找点匹配B
int h[N],e[M],ne[M],idx;
int match[N]; 
bool vis[N],st[N];
//三个数组维护的含义见上面或下面
int n1,n2,m;
"n1+n2是总顶点数,n1是A集合中顶点数,n2是B集合中顶点数,由题目要求限制"

void add(int a,int b)
{
    
    
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int find(int v)
{
    
    
    for (int i=h[v];~i;i=ne[i]) {
    
    
        int j=e[i];
        if (!vis[j] && !st[j]) {
    
    
            if (match[j]==0) {
    
    match[j]=v; return true;}
            else {
    
    
                st[j]=true;
                if (find(match[j])) {
    
    match[j]=v; return true;}
                else vis[j]=true;
            }//此时说明B堆中的j结点与A堆中的结点match[j]是板上钉钉的匹配了,不能再改了,
        }    //所以后面的点再匹配就不用再找我了,
    }
    return false;
}

int main()
{
    
    
    memset(h,-1,sizeof h);
    read(n1),read(n2),read(m);//A堆顶点数n1,B堆顶点数n2,边数m
    int a,b;
    while (m--) {
    
    
        read(a),read(b);
        add(a,b);"两个堆中结点编号重复,这里无影响,也可以add(a,n1+b);"
    }
    int res=0; //统计最大匹配的边数
    for (int i=1;i<=n1;i++) {
    
    
        memset(st,false,sizeof st); //每次初始化一下st数组,重新禁止一些匹配。
        if(find(i)) res++; 
    }
    printf("%d",res);
    
    return 0;
}

matriz de coincidencias:
atraviesa el montón A y almacena los bordes de A-> B. En este momento, igualar [i] = j; significa que el vértice i en la pila B coincide con el vértice j en la pila A. Dado que los subíndices de los vértices en el gráfico comienzan todos desde 1, cuando coincide [i] = 0 , significa Sin coincidencia todavía.

st array:
La función del st array es que cuando un punto izquierdo coincide con un punto que ya tiene un objeto a la derecha, el punto derecho corresponde al punto izquierdo del lado para encontrar un nuevo "objeto", no más Para encontrar el punto a la derecha del original, debido a la recursividad múltiple, los puntos prohibidos antes de cada recursión deben registrarse, así que cree una matriz st y restablezca la matriz st a falso cada vez que se inicie una nueva coincidencia.

vis array: El
vis array se usa para registrar los puntos que no están seleccionados en el montón B. Cuando el punto en el montón B solo coincide con el punto en el montón A, está bloqueado, por lo que no encuentra (es necesario para que coincida con []).

En la versión principal, quiero usar match [j]! = X in if (! Vis [j] && match [j]! = X) para reemplazar la función de la matriz st, pero debido a que cada recursión prohibirá aj, y esto es solo. La j actual será prohibida, y no tendrá ningún efecto sobre la j anterior, lo que fácilmente causará un bucle sin fin. Pila de ráfagas.

 bool find(int x)
{
    
    
    for (int i = h[x]; i != -1; i = ne[i])  {
    
    
        int j=e[i];
        if (!vis[j] && match[j]!=x) {
    
    
            if (match[j]==0) {
    
    match[j]=x; return true;}
            else {
    
    
                if (find(match[j])) {
    
    match[j]=x; return true;}
                else vis[j] = true;
            }                     
        }
    }
    return false;
}

El juicio de la línea 5 es diferente, lo cual es incorrecto.

Supongo que te gusta

Origin blog.csdn.net/HangHug_L/article/details/114106714
Recomendado
Clasificación