图论四

复健Day7

图论四

如果一张无向图的N个节点可以分成A,B两个不相交的非空集合,并且同一集合内的点之间没有边相连,那么称改无向图为二分图

二分图不存在奇环(长度为奇数的环)

因为每一条边都是从一个集合走到另一个集合,只有走偶数次才能回到出发点

1.二分图判定(染色法)

用染色法来判定二分图,若标记过程中出现冲突,则说明图中产生了奇环,不是二分图

时间复杂度O(n+m)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 100010
using namespace std;

int head[maxn],tot;

struct Edge
{
	int v,nxt;
	Edge(){}
	Edge(int v,int nxt):v(v),nxt(nxt){}
}ed[maxn<<1];

void add(int u,int v)
{
	ed[tot]=Edge(v,head[u]);
	head[u]=tot++;
}

int color[maxn];

bool dfs(int u,int c)//1表示有奇环 
{
	color[u]=c;
	for(int i=head[u];~i;i=ed[i].nxt)
	{
		int v=ed[i].v;
		if(!color[v])//初始化为0,被染色为1和2
		{
			if(dfs(v,3-c)) return 1;
		}
		else if(color[v]==c) return 1;
	}
	return 0;
}

int main()
{
	int n,m;
	cin>>n>>m;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=m;i++)
	{
		int u,v;
		cin>>u>>v;
		add(u,v);add(v,u);
	}
	bool flag=0;
	for(int i=1;i<=n;i++)
	{
		if(!color[i])
		{
			if(dfs(i,1))
			{
				flag=1;
				break;
			}
		}
	}
	if(flag) printf("No");//表示不是二分图
	else printf("Yes\n");
	return 0;
}

2.二分图最大匹配(匈牙利算法)

匈牙利算法:通过不停地找增广路来增加匹配边

时间复杂度O(nm)

https://www.luogu.com.cn/problem/P3386

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn=1e5+10;

int head[maxn],tot;

struct Edge
{
	int v,nxt;
	Edge(){}
	Edge(int v,int nxt):v(v),nxt(nxt){}
}ed[maxn];//存单向边就可以了,让左选右

void add(int u,int v)
{
	ed[tot]=Edge(v,head[u]);
	head[u]=tot++;
}

int match[maxn],vis[maxn];

bool dfs(int u)
{
	for(int i=head[u];~i;i=ed[i].nxt)
	{
		int v=ed[i].v;
		if(vis[v]) continue;
		vis[v]=1;
		if(!match[v]||dfs(match[v]))
		{
			match[v]=u;
			return 1;
		}
	}
	return 0;
}

int main()
{
	int n,m,k;
	cin>>n>>m>>k;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=k;i++)
	{
		int u,v;
		cin>>u>>v;
		add(u,v+n);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(vis,0,sizeof(vis));
		if(dfs(i)) ans++;
	}
	printf("%d\n",ans);
	return 0;
}

3.二分图最大匹配(Dinic算法)

给二分图创建虚拟源点和汇点,将源点连上左边所有节点,右边所有节点连汇点,容量均为1,原来的每条边从左往右连,容量也均为1,这样我们就把二分图转换成了网络流模型

最大流即为最大匹配

时间复杂度O(nm)

https://www.luogu.com.cn/problem/P3386

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define int long long
using namespace std;

const int maxn=1e6+10;

int head[maxn],tot;
int n,m;
int cur[maxn];

int d[maxn];

struct Edge
{
	int v,c,nxt;
	Edge(){}
	Edge(int v,int c,int nxt):v(v),c(c),nxt(nxt){}
}ed[maxn];

void add(int u,int v,int c)
{
	ed[tot]=Edge(v,c,head[u]);
	head[u]=tot++;
}

bool bfs()
{
	memset(d,0,sizeof(d));
	queue<int> q;
	q.push(0);
	d[0]=1;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];~i;i=ed[i].nxt)
		{
			int v=ed[i].v,c=ed[i].c;
			if(d[v]==0&&c)
			{
				d[v]=d[u]+1;
				q.push(v);
				if(v==n+m+1) return 1;
			}
		}
	}
	return 0;
}

int dfs(int u,int mf)
{
	if(u==n+m+1) return mf;
	int sum=0;
	for(int i=cur[u];~i;i=ed[i].nxt)
	{
		cur[u]=i;
		int v=ed[i].v;
		if(d[v]==d[u]+1&&ed[i].c)
		{
			int f=dfs(v,min(mf,ed[i].c));
			ed[i].c-=f;
			ed[i^1].c+=f;
			mf-=f;
			sum+=f;
			if(mf==0) break;
		}
	}
	if(sum==0) d[u]=0;
	return sum;
}

int dinic()
{
	int flow=0;
	while(bfs())
	{
		memcpy(cur,head,sizeof(head));
		flow+=dfs(0,1e9);
	}
	return flow;
}

signed main()
{
	memset(head,-1,sizeof(head));
	int e;
	cin>>n>>m>>e;
	for(int i=1;i<=e;i++)
	{
		int x,y;
		cin>>x>>y;
		add(x,y+n,1);add(y+n,x,0);
	}
	for(int i=1;i<=n;i++)
	{
		add(0,i,1);add(i,0,0);
	}
	for(int i=1;i<=m;i++)
	{
		add(i+n,n+m+1,1);add(n+m+1,i+n,0);
	}
	printf("%lld\n",dinic());
	return 0;
}

4.二分图最大权完美匹配(KM算法)

给定一个带边权的二分图,其左部、右部点数相等,均为N个点,如果最大匹配有N跳变,则称二分图的完美匹配

二分图的边权和最大的完美匹配称为二分图的最大权完美匹配

https://www.luogu.com.cn/problem/P6577


posted on   dolires  阅读(10)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示