二分图最小点覆盖:最少的点来覆盖所有的边,等于最大匹配数
二分图最大独立集:最大的点集满足点集内没有边(两两互相不可达),等于总点数-最大匹配数
有向无环图最小路径点覆盖:在有向图中,找出最少的路径使路径经过所有点.(每条路径经过的点不相同).先将有向图转化成二分图,每个点拆成两个点,一个出边,一个入边,再进行最大匹配,最小路径点覆盖等于有向图总点数-最大匹配数
有向无环图最小路径重复点覆盖:每条路径经过的点可以相同,先对有向图求传递闭包,再求最小路径覆盖.
有向无环图最大独立集:最大的点集满足点集内没有边,等于最小路径重复点覆盖.
有向图的传递闭包
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
g[i][j]|=g[i][k]&&g[k][j];
染色法判断二分图
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+10;
int h[N],nex[N<<1],to[N<<1],con=1;
int c[N],vis[N];
int dfs(int x)//O(n+m)不含奇数环即为二分图
{
vis[x]=1;
int d=c[x]==1?-1:1;
for(int i=h[x];i;i=nex[i])
{
if(!c[to[i]])
{
c[to[i]]=d;
dfs(to[i]);
}
if(c[to[i]]==c[x])
return 1;
}
return 0;
}
int main()
{
int n,m;cin>>n>>m;
while(m--)
{
int a,b;scanf("%d%d",&a,&b);
nex[con]=h[a];
h[a]=con;
to[con++]=b;
nex[con]=h[b];
h[b]=con;
to[con++]=a;
}
int f=0;
for(int i=1;i<=n;++i)
{
if(!vis[i])
{
c[i]=1;
f=max(f,dfs(i));
}
}
if(f)
cout<<"No"<<endl;
else
cout<<"Yes"<<endl;
return 0;
}
匈牙利算法进行二分图的最大匹配
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=512,M=1e5+10;
int h[N],nex[M],to[M],con=1;
int match[N],vis[N];
int find(int x)
{
for(int i=h[x];i;i=nex[i])
{
if(!vis[to[i]])
{
vis[to[i]]=1;
if(!match[to[i]]||find(match[to[i]]))
{
match[to[i]]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int n1,n2,m;cin>>n1>>n2>>m;
while(m--)
{
int a,b;scanf("%d%d",&a,&b);
nex[con]=h[a];
h[a]=con;
to[con++]=b;
}
int ans=0;
for(int i=1;i<=n1;++i)
{
memset(vis,0,sizeof(vis));
ans+=find(i);
}
cout<<ans<<endl;
return 0;
}
如果是无向图需要先进行一次dfs将从左向右的边标出来
const int N=128;
int h[N*N],to[128*128*4*2],nex[128*128*4*2],con=1,w[128*128*4*2];
int vis[N*N],mat[N*N];
void add(int a,int b)
{
nex[con]=h[a];
h[a]=con;
to[con++]=b;
}
void dfs1(int now,int l)
{
if(vis[now])
return;
vis[now]=1;
for(int i=h[now];i;i=nex[i])
{
if(l)
{
w[i]=1;
check++;
}
dfs1(to[i],l^1);
}
return;
}
int dfs(int now)
{
for(int i=h[now];i;i=nex[i])
{
if(!w[i])
continue;
if(vis[to[i]])
continue;
vis[to[i]]=1;
if(!mat[to[i]]||dfs(mat[to[i]]))
{
mat[to[i]]=now;
return 1;
}
}
return 0;
}
int main()
{
freopen("1.txt","r",stdin);
int n,ans=0;//n为无向图总点数
for(int i=1;i<=n;++i)
dfs1(i,1);//标记从左到右的边
for(int i=1;i<=n;++i)//匈牙利算法
{
memset(vis,0,sizeof(vis));
if(dfs(i))
ans++;
}
cout<<ans<<endl;
return 0;
}