[Study notes] bipartite graph

In fact, the concept of bloggers can not remember clearly what

binary picture

FIG point can be perfectly divided into two parts, such that a portion of each dot is not mutually connected edges

Or: it can be dyed black and white, no odd ring

Decision

Direct (dfs \) \ staining

\(Code\)

	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 ;
	}

Here \ (col [\ space] \ ) is set for each point represents the point belongs numeral

I first wrote that according to \ (0 \) go this way, you can have \ (2 \) (that is, \ (col \) calculation of the time to take \ (3 \) reduced chant)

Maximum matching

Match: a set of edges of the bipartite graph, so that the side edges is not set all the public endpoints

Maximum Matching: Edge concentrate \ (size \) one of the largest

Matching side: As the name suggests, the side edge set match

Augmenting path (interleaved way): a path from the connection point of the left portion of the non-matching and non-matching point in the right portion

Such that the matching and non-matching side edges appear alternately, an odd number length should be

This definition is the augmenting path, so that we can put all the edges on the path negated at a time to find augmenting paths, then side set size will be \ (+ 1 \)

Seeking :(, two)

1. Network maximum flow: \ (Dinic \)

This approach is lazy and do not want to learn a bipartite graph of people do (bloggers to engage in a direct network streams began to think not learn a bipartite graph with)

Put the code is \ (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. Hungary algorithm

Dfs is the time to find an augmenting path, if found the answer plus \ (1 \)

Code or put this question can probably consider compare, Hungary is good: good back \ (+ \) Short

#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();}

Coming here to study the above two plates have a question: SHOI2002 party

Bloggers more vegetables, so the questions are questions the board (the board really really eh)

Minimum Vertex Cover

In the bipartite graph of a set of points, such that all sides have the figures in this end point set (true intelligibility defined)

\ (König \) Theorem:

The bipartite graph of the minimum spot size to cover set \ (= \) Size bipartite graph maximum matching set

Start with the smallest point method of constructing covered:

  1. Find the maximum matching.

  2. The right of each match point of departure is not looking for augmenting paths (must have failed, or else it is not the biggest matches), the node labeled visited.

  3. Take a left marker portion, a right portion unmarked points, constituting a set of minimum coverage.

Figure painting can be understood

Then the proof:

After the above-described construction method

No match point right part must be marked point - because they are the starting point

No match left part of the point is not necessarily mark the point - if it is found to be marked augmenting path (both sides are not matching point eh)

A pair of matching points are marked or labeled none - because the left portion of the matching point can only be reached by the right portion

Take a left marker portion, a right portion unlabeled point, such that each pair of matching points just been removed a

So the number of values ​​equal


Matching edges must be covered - for each pair of matching a point removed

Edge connects two points did not match does not exist - otherwise appear augmenting path contains only one side

Connecting the left and right portions matching points unmatched edge points - which is the starting point, the former must be labeled

Connecting the left side part and right not match point match point - which is not marked, otherwise there is augmenting path

So all sides are covered, we're done

Example: UVA1194 - Machine Schedule

Was a board problem, read the meaning of the questions on it

#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();}

Maximum Independent Set

Definition: any two points in the figures are not connected to the edge point set called independent set of FIG.

Theorem: bipartite graph maximum independent set \ (= \) points in FIG \ (- \) bipartite graph maximum matching

Proof: choose the most independent set of dots

\ (\ Leftrightarrow \) to remove the minimum point in the drawing, so that no edge between the remaining points.

\ (\ Leftrightarrow \) covering all sides with a minimum point, to remove the smallest coverage.

Very good understanding of it

Example: Knight placement

Given a \ (n \ times m \) rectangular ban placed in several points, several requirements put up Knight

First, see whether it was seeking the largest independent set is not difficult

Built on the current figure is the point of view of the construction site and can be attacked on the line

A good \ (Trick \) :

We found the location where the knight can attack and to position \ (id \) is not the same

(Where \ (ID \) is the sum of horizontal and vertical coordinates)

This can be omitted \ (dfs \) dyeing process, and when built directly look at the map of parity on it

Note: Obstacles point here is not to write \ (while (t -) \ )

The reason is that \ (t \) statistics even when the answer is lost in the back, if not the cut is finished (the author card for half an hour)

Code:

#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();}

Guess you like

Origin www.cnblogs.com/yspm/p/12637929.html