[Notas de estudio] bipartito gráfico

De hecho, el concepto de los bloggers no puede recordar claramente lo

bipartito figura

punto de la figura puede ser perfectamente dividido en dos partes, tales bordes que una porción de cada punto no está conectado mutuamente

O: puede ser en blanco y negro teñido, sin anillo impar

decisión

Directos (DFS) \ \ tinción

\(Código\)

	inline void dfs1(int x)
	{
		for(int i=head[x];i;i=e[i].nxt) 
		{
			int t=e[i].to;
			if(col[t]==-1) col[t]=1-col[x],dfs1(t);
		}return ;
	}

Aquí \ (col [\ espacio] \ ) se establece para cada punto representa el punto pertenece numeral

Escribí por primera vez que, de acuerdo a \ (0 \) ir de esta manera, puede hacer que \ (2 \) (es decir, \ (col \) cálculo de la hora de tomar \ (3 \) reducida canto)

coincidente máximo

Coincidir: un conjunto de aristas del grafo bipartito, de manera que los bordes laterales no se ha establecido todos los puntos finales públicas

concentrado Edge: Coincidencia máxima \ (tamaño \) uno de los mayores

lateral a juego: Como su nombre indica, el partido conjunto borde lateral

trayectoria de aumento (forma intercalada): un camino desde el punto de conexión de la parte izquierda del punto de no coincidencia y no coincidencia en la parte derecha

De tal manera que los bordes laterales coincidentes y no coincidentes aparecen alternativamente, una longitud de número impar debe ser

Esta definición es la trayectoria de aumento, por lo que podemos poner todas las aristas en el camino negado a la vez para encontrar caminos aumentar, entonces el tamaño del conjunto lado será \ (1 + \)

Buscando :(, dos)

1. Red de flujo máximo: \ (Dinic \)

Este enfoque es perezoso y no quiere aprender un grafo bipartito de personas (bloggers a participar en una red directa corrientes comenzaron a pensar no ha entrenado con un grafo bipartito con)

Poner el código es \ (LGOJ2055 \) Holiday Hostel

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1010; 
	struct node{
		int nxt,to,lim;
	}e[N<<1];
	int head[N],cnt=1,dep[N],n,S,T,inf=1e15+10; 
	inline void add2(int u,int v,int w)
	{
		e[++cnt].lim=w; e[cnt].nxt=head[u]; e[cnt].to=v;
		return head[u]=cnt,void();
	}
	inline void add1(int u,int v,int w)
	{
		add2(u,v,w); add2(v,u,0);
		return ;
	}
	inline bool bfs()
	{
		queue<int> q; q.push(S); memset(dep,-1,sizeof(dep)); dep[S]=0;
		while(!q.empty())
		{
			int fr=q.front(); q.pop();
			for(int i=head[fr];i;i=e[i].nxt)
			{
				if(e[i].lim<=0) continue;
				int t=e[i].to;
				if(dep[t]!=-1) continue;
				dep[t]=dep[fr]+1; q.push(t);
			}
		}
		return dep[T]!=-1; 
	}
	inline int dfs(int now,int in)
	{
		if(now==T) return in; int out=0;
		for(int i=head[now];i;i=e[i].nxt)
		{
			if(e[i].lim<=0) continue;
			int t=e[i].to;
			if(dep[t]!=dep[now]+1) continue;
			int res=dfs(t,min(e[i].lim,in)); 
			e[i].lim-=res; e[i^1].lim+=res; 
			in-=res; out+=res; 
		}
		if(!out) dep[now]=0; 
		return out;
	}
	inline void prework()
	{
		memset(head,0,sizeof(head)); memset(e,0,sizeof(e)); cnt=1;
		return ;
	}
	int st[N],at[N];
	inline void work()
	{
		prework(); int num=0;
		n=read();  S=n<<1|1; T=S+1;
		for(int i=1;i<=n;++i) 
		{
			st[i]=read();
			if(st[i]) add1(i+n,T,1);
		}
		for(int i=1;i<=n;++i) at[i]=read();
		for(int i=1;i<=n;++i)
		{
			if(!st[i]||(st[i]&&!at[i])) add1(S,i,1),num++;
		}
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=n;++j)
			{
				int fl=read();
				if(i==j||fl) add1(i,j+n,1);
			}
		}
		int ans=0;
		while(bfs()) ans+=dfs(S,inf);
		puts(num<=ans?"^_^":"T_T");
		return ;
	}
	signed main()
	{
		int T=read(); while(T--) work(); 
		return 0;
	}
}
signed main(){return yspm::main();}

2. algoritmo Hungría

DFS es el tiempo para encontrar una trayectoria de aumento, si se considera la respuesta más \ (1 \)

Código o poner esta pregunta probablemente puede considerar comparan, Hungría es bueno: buena vuelta \ (+ \) Corto

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1010; 
	struct node{
		int to,nxt;
	}e[N<<1];
	int head[N],cnt,n,to[N];
	inline void add(int x,int y)
	{
		e[++cnt].nxt=head[x]; e[cnt].to=y;
		return head[x]=cnt,void();
	}
	inline void prework()
	{
		cnt=0; memset(head,0,sizeof head); memset(e,0,sizeof(e));
		memset(to,-1,sizeof(to));
		return ;
	}
	bool r[N][N],fl[N],at[N],vis[N];
	inline bool dfs(int x)
	{
		for(int i=head[x];i;i=e[i].nxt)
		{
			int t=e[i].to; if(vis[t]) continue;
			vis[t]=1; if(to[t]==-1||dfs(to[t])) return to[t]=x,1;
 		}
		return 0;
	}
	inline void work()
	{
		prework(); n=read();
		for(int i=1;i<=n;++i) fl[i]=read();
		for(int i=1;i<=n;++i) at[i]=read();
		int cnt=0; for(int i=1;i<=n;++i) if(!fl[i]) cnt++,at[i]=0; else if(!at[i]) cnt++;
		for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) r[i][j]=read(); 
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=n;++j)
			{
				
				if(i==j&&fl[i]) add(i,i);
				else if(r[i][j]&&fl[i]) add(j,i);
			}
		}
		int ans=0;
		for(int i=1;i<=n;++i)
		{
			memset(vis,0,sizeof(vis));
			if(!at[i]&&dfs(i)) ans++;
		}
		puts(ans>=cnt?"^_^":"T_T");
		return ;
	}
	signed main()
	{
		int T=read(); while(T--) work();
		return 0;
	}
}
signed main(){return yspm::main();}

Venir aquí a estudiar las dos placas anteriores han una pregunta: partido SHOI2002

Los bloggers más verduras, por lo que las preguntas son preguntas de la tabla (el consejo realmente eh)

Cobertura mínima Vertex

En el gráfico bipartito de un conjunto de puntos, de manera que todos los lados tienen las figuras de este conjunto de puntos de extremo (true inteligibilidad define)

\ (König \) Teorema:

El gráfico bipartito del tamaño de punto mínimo a sistema de la cubierta \ (= \) bipartito conjunto gráfico coincidencia máxima Tamaño

Comenzar con el método de punto más pequeño de la construcción de cubiertas:

  1. Encontrar la coincidencia máxima.

  2. El derecho de cada punto de partida partido no está mirando para aumentar caminos (debe haber fallado, o de lo contrario no son los partidos más importantes), el nodo etiquetado visitado.

  3. Tomar una porción marcador izquierdo, una porción derecha sin marcar puntos, lo que constituye un conjunto de cobertura mínima.

Figura pintura puede entenderse

Entonces la prueba:

Después de que el método de construcción descrito anteriormente

Ninguna parte match point derecho debe ser punto marcado - porque son el punto de partida

Ningún resultado dejó parte del punto no es necesariamente marcar el punto - si se comprueba que ser marcada trayectoria de aumento (ambos lados no son punto de coincidencia eh)

Un par de puntos coincidentes están marcados o ninguno etiquetada - porque la porción izquierda del punto de coincidencia sólo puede ser alcanzado por la porción derecha

Tomar una parte marcador izquierda, un punto no marcado porción derecha, de manera que cada par de puntos coincidentes simplemente sido un eliminado

Por lo que el número de valores es igual


bordes a juego deben estar cubiertos - para cada par de búsqueda de un punto eliminado

Edge conecta No se han encontrado no existen dos puntos - de lo contrario aparecerá trayectoria de aumento contiene un solo lado

Conexión de las porciones izquierda y derecha que emparejan puntos puntos de borde incomparables - que es el punto de partida, el primero debe ser etiquetados

Conexión de la parte lateral izquierda y derecha no coincide con el punto de partido punto - que no está marcado, de lo contrario existe trayectoria de aumento

Así que todas las partes están cubiertas, hemos terminado

Ejemplo: UVA1194 - Horario Máquina

Era un problema con la placa, leer el significado de las preguntas sobre el mismo

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1e5+10;
	struct node{
		int to,nxt;
	}e[N<<1];
	int head[N],cnt,n,m,k;
	inline void add(int u,int v)
	{
		e[++cnt].nxt=head[u]; e[cnt].to=v;
		return head[u]=cnt,void();
	}
	int to[N]; bool vis[N];
	inline bool dfs(int x)
	{
		for(int i=head[x];i;i=e[i].nxt)
		{
			int t=e[i].to; if(vis[t]) continue;
			vis[t]=1; if(!to[t]||dfs(to[t])) return to[t]=x,1;
		}return 0;
	}
	int ans=0;
	inline void prework()
	{
		memset(head,0,sizeof(head));
		memset(e,0,sizeof(e));
		memset(to,0,sizeof(to)); 
		ans=0; cnt=0; 
		return ;
	}
	inline void work()
	{
		m=read(); k=read();
		for(int i=1;i<=k;++i)
		{
			read();
			int u=read(),v=read();
			add(u,v); 	
		}
		for(int i=1;i<=n;++i)
		{
			memset(vis,0,sizeof(vis)); 
			if(dfs(i)) ans++; 
		} cout<<ans<<endl;
		return prework();
	}
	signed main()
	{
		while(n=read()) work();
		return 0;
	}
}
signed main(){return yspm::main();}

Máximo conjunto independiente

Definición: cualesquiera dos puntos en las figuras no están conectados al conjunto de puntos de borde llamado conjunto independiente de la fig.

Teorema: Gráfico máximo conjunto independiente bipartito \ (= \) puntos en la figura \ (- \) bipartito gráfico juego máximo

Prueba: elegir el conjunto más independiente de los puntos

\ (\ Leftrightarrow \) para eliminar el punto mínimo en el dibujo, de modo que ningún borde entre los puntos restantes.

\ (\ Leftrightarrow \) que cubre todos los lados con un punto mínimo, para eliminar la cobertura más pequeña.

Muy buena comprensión de la misma

Ejemplo: colocación Knight

Dado un \ (n \ m veces \) prohibición rectangular colocada en varios puntos, una serie de requisitos puso Knight

En primer lugar, ver si se busca el mayor conjunto independiente no es difícil

Construida sobre la actual cifra es el punto de vista de la obra de construcción y puede ser atacado en la línea

Una buena \ (Trick \) :

Encontramos el lugar en el que el caballero puede atacar y a la posición \ (id \) no es lo mismo

(Donde \ (ID \) es la suma de las coordenadas horizontales y verticales)

Esto se puede omitir \ (DFS \) proceso de teñido, y fecha de construcción mire directamente al mapa de la paridad en él

Nota: Los obstáculos punto aquí no es escribir \ (tiempo (t -) \ )

La razón es que \ (t \) estadísticas aun cuando la respuesta se pierde en la parte de atrás, si no el corte está terminado (la tarjeta autor durante media hora)

Código:

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=10010;
	struct node{
		int to,nxt;
	}e[N<<6];
	int n,m,head[N],cnt,to[N],k;
	bool g[210][201],vis[N];
	inline void add(int u,int v)
	{
		e[++cnt].nxt=head[u],e[cnt].to=v;
		return head[u]=cnt,void();
	}
	inline int get(int x,int y){return m*(x-1)+y;}
	inline bool dfs(int x)
	{
		for(int i=head[x];i;i=e[i].nxt)
		{
			int t=e[i].to; if(vis[t]) continue;
			vis[t]=1; if(!to[t]||dfs(to[t])) return to[t]=x,1;
		}
		return 0;
	}
	inline void max_match()
	{
		int ans=n*m-k; 
		for(int i=1;i<=n;++i) 
		{
			for(int j=1;j<=m;++j)
			{
				if(g[i][j]||(i+j)%2==1) continue; 
				else 
				{
					memset(vis,0,sizeof(vis));
					if(dfs(get(i,j))) 
					{
						ans--;
					}
				}
			}
		} 
		return printf("%lld\n",ans),void();
	}
	int fx[8]={-1,-1,-2,-2,1,1,2,2};
	int fy[8]={-2,2,-1,1,-2,2,-1,1};
	inline bool in(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m;}
	signed main()
	{
		n=read(); m=read(); k=read();
		for(int i=1;i<=k;++i) 
		{
			int x=read(),y=read(); g[x][y]=1;
		} 
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=m;++j)
			{
				if((i+j)%2==1||g[i][j]) continue;
				for(int k=0;k<8;++k)
				{
					int tx=i+fx[k];
					int ty=j+fy[k];
					if(!in(tx,ty)||g[tx][ty]) continue;
					add(get(i,j),get(tx,ty));
				}
			}
		}
		max_match();
		return 0;
	}
}
signed main(){return yspm::main();}

Supongo que te gusta

Origin www.cnblogs.com/yspm/p/12637929.html
Recomendado
Clasificación