二分图总结

1. 二分图的判定:染色法。\(O(n+m)\)

void dfs(int x)
{
	int i,j;
	for(i=head[x];i;i=e[i].nxt)
	{
		int to=e[i].to;
		if(!c[to])
		{
			c[to]=3-c[x];
			dfs(to);
		}
		else if(c[to]==c[x])
		{
			pd=0;
			return;
		}
	}
}

2. 二分图最大匹配:

匈牙利算法(增广路算法): \(O(n*m)\)

dinic(网络流算法):\(O(\sqrt n*m)\)

bool dfs(int x)
{
	int i,j;
	vis[x]=1;
	for(i=head[x];i;i=a[i].nxt)
	{
		int to=a[i].to;
		if(vis[to]) continue;
		vis[to]=1;
		if(!match[to]||dfs(match[to]))
		{
			match[to]=x;
			return true;
		}
	}
	return false;
}
for(i=1;i<=n;i++)
{
	memset(vis,0,sizeof(vis));
	if(dfs(i)) ans++;
}

3. 最小点覆盖=最大匹配


4. 最大独立集=总点数-最大匹配


5. 有向无环图中:

a. 最小边覆盖=最小路径点覆盖:

选取最少的路径,使得每个定点均属于一条路径,路径长度可以为0。

与二分图的关系:将每个点拆成入点和出点,最小路径覆盖=原图总点数-拆点后的图的最大匹配

b. 最大团:任意两点之间都有边相连的最大子图

无向图\(G\)的最大团等于它补图的最大独立集。

c. 最小路径可重点覆盖

有向无环图\(G\)的最小路径可重点覆盖,等价于先对有向图传递闭包,得到有向无环图\(G'\),再在\(G'\)上求一般的(路径不可相交的)最小路径点覆盖。


6. 可用网络流dinic求解

例:「UVA1411」Ants:

因为两条相交线段长度必然大于分别直接相连,所以答案就是二分图上跑最小费用流,使用类dinic算法,时间复杂度上届为\(O(nmf)\)\(f\)为流量。

#include<bits/stdc++.h>
#define ll long long
#define N 500
#define M 600000
#define eps 1e-5
using namespace std;
int head[N],n,cnt=2,S,T,inf=1e9+7,vis[N];
struct note{
	double x,y;
}b[N],W[N];
struct edge{
	int to,nxt,sz;
	double w;
}a[M];
void add(int x,int y,int s,double z)
{
	a[cnt].to=y;
	a[cnt].sz=s;
	a[cnt].nxt=head[x];
	a[cnt].w=z;
	head[x]=cnt++;
	if(s!=0) add(y,x,0,-z);
}
double calc(note x,note y){
	return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
} 
int ans=inf;
double dis[N];
deque<int> q;
bool spfa()
{
	int i,j;
	memset(vis,0,sizeof(vis));
	for(i=S;i<=T;i++) dis[i]=inf;
	while(!q.empty()) q.pop_front();
	q.push_back(S);dis[S]=0;
	vis[S]=1;
	while(!q.empty())
	{
		int now=q.front();q.pop_front();
		vis[now]=0;
		for(i=head[now];i;i=a[i].nxt)
		{
			int to=a[i].to;
			if(a[i].sz&&dis[to]-dis[now]-a[i].w>eps)
			{
				dis[to]=dis[now]+a[i].w;
				if(!vis[to])
				{
					vis[to]=1;
					if(!q.empty()&&dis[to]<dis[q.front()]) q.push_front(to);
					else q.push_back(to);
				}
			}
		}
	}
	return dis[T]!=inf;
}
int cur[N];
int cost=0,maxflow;
int dinic(int x,int flow)
{
	int i,j,sum=0;
	vis[x]=1;
	if(x==T||!flow) return flow;
	for(i=cur[x];i;i=a[i].nxt)
	{
		cur[x]=i;
		int to=a[i].to;
		if(fabs(dis[to]-dis[x]-a[i].w)<eps&&a[i].sz&&!vis[to])
		{
			int f=dinic(to,min(a[i].sz,flow-sum));
			if(!f) continue;
			sum+=f;
			a[i].sz-=f;
			a[i^1].sz+=f;
			cost+=f*a[i].w;
			if(!flow) break;
		}
	}
	return sum;
}
void solve()
{
	while(spfa())
	{
		vis[T]=1;
		while(vis[T])
		{
			memcpy(cur,head,sizeof(head));
			memset(vis,0,sizeof(vis)); 
			maxflow+=dinic(S,inf);
			ans=min(ans,cost);
		}
	}
}
int main()
{
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%lf%lf",&b[i].x,&b[i].y);
	for(i=1;i<=n;i++) scanf("%lf%lf",&W[i].x,&W[i].y);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
		//	if(i==j) continue;
			double D=calc(b[i],W[j]);
			add(i,j+n,1,D);
		}
	}
	S=0,T=2*n+1;
	for(i=1;i<=n;i++)
	{
		add(S,i,1,0);
		add(i+n,T,1,0); 
	}
	solve();
	for(i=1;i<=n;i++)
	{
		for(j=head[i];j;j=a[j].nxt)
		{
			int to=a[j].to;
			if(!a[j].sz)
			{
				printf("%d\n",to-n);
			    break;
			} 
		}
	}
	return 0;
} 
posted @ 2020-10-30 11:41  yzxx_qwq  阅读(113)  评论(0编辑  收藏  举报