判定
变量
- bool is2f:标记是否是二分图。
- int v[i]:标记节点 i 的颜色。
函数
- Bipartite_Graph():初始化。
- void dfs(int x,int col):将节点 x 的颜色染为 col,并给其他没染色的点染色。
- bool calc():判断 G 是否是二分图。
代码
struct Bipartite_Graph{
bool is2f;
int v[N];
Bipartite_Graph(){
is2f=1;
memset(v,0,sizeof(v));
}
void dfs(int x,int col){
if(!is2f)
return;
v[x]=col;
for(int i=G.head[x];i;i=G.nxt[i]){
int y=G.ver[i];
if(v[y]==0)
dfs(y,3-col);
else if(v[y]==col){
is2f=0;
return;
}
}
}
bool calc(){
for(int i=1;i<=n;i++)
if(!v[i]&&is2f)
dfs(i,1);
return is2f;
}
}tu;
最大匹配
变量
- int v[i]:标记节点 i 所在的增广路的起点。
- int match[i]:标记节点 i 配对的点。
函数
- bool dfs(int x,int tag):求现在再找一条从节点 x 开始,起点为 tag 的增广路是否可行。
- int ask_max(int n):求左部有 n 个节点的最大匹配。
代码
struct Bipartite_Graph{
int v[N];
int match[N];
bool dfs(int x,int tag){
if(v[x]==tag)
return 0;
v[x]=tag;
for(int i=G.head[x];i;i=G.nxt[i]){
int y=G.ver[i];
if(!match[y]||dfs(match[y],tag)){
match[y]=x;
return 1;
}
}
return 0;
}
int ask_max(int n){
int ans=0;
memset(v,0,sizeof(v));
memset(match,0,sizeof(match));
for(int i=1;i<=n;i++)
if(dfs(i,i))
ans++;
return ans;
}
}tu;
最大权匹配
变量
- const long long INF:极大值,不会有一条边的绝对值超过它。
- int n:右部节点的个数,要保证左部节点的个数一定比右部的少。
- int pre[i]:搜索树上一条非匹配边 pre[i]←i,其中 i 是右部点。
- int matcha[i]:搜索树上一条匹配边 i→matcha[i],其中 i 是左部点。
- int matchb[i]:搜索树上一条匹配边 matchb[i]→i,其中 i 是右部点。
- int va[i]:左部点 i 是否被访问过。
- int vb[i]:右部点 i 是否被访问过。
- long long w[i][j]:边 i→j 的权值,不存在则为 -INF。
- long long la[i]:左部点 i 的可行顶标。
- long long lb[i]:右部点 i 的可行顶标。
- long long slack[i]:右部点 i 的松弛值,即 maxj{la[j]+lb[i]-w[j][i]}。
- long long delta:可行顶标可变化的最大值。
- queue<int>q:队列。
函数
- void init():初始化边权。
- void bfs(int s):以 s 为起点进行 bfs。
- ll km():计算二分图最大权匹配。
代码
struct Bipartite_Graph_Perfect_Matching{
const long long INF=(1ll<<60);
int n,pre[N],matcha[N],matchb[N];
bool va[N],vb[N];
ll w[N][N],la[N],lb[N],slack[N],delta;
queue<int>q;
void init(){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
w[i][j]=-INF;
}
void bfs(int s){
memset(va,0,sizeof(va));
memset(vb,0,sizeof(vb));
for(int i=1;i<=n;i++)
slack[i]=INF;
while(q.size())
q.pop();
q.push(s);
while(1){
while(q.size()){
int x=q.front();
q.pop();
va[x]=1;
for(int y=1;y<=n;y++)
if(!vb[y])
if(la[x]+lb[y]-w[x][y]<slack[y]){
slack[y]=la[x]+lb[y]-w[x][y];
pre[y]=x;
if(!slack[y]){
vb[y]=1;
if(!matchb[y]){
int z=y;
while(z){
matchb[z]=pre[z];
swap(matcha[pre[z]],z);
}
return;
}
else
q.push(matchb[y]);
}
}
}
delta=INF;
for(int i=1;i<=n;i++)
if(!vb[i])
delta=min(delta,slack[i]);
for(int i=1;i<=n;i++){
if(va[i])
la[i]-=delta;
if(vb[i])
lb[i]+=delta;
else
slack[i]-=delta;
}
for(int y=1;y<=n;y++){
if(!vb[y])
if(!slack[y]){
vb[y]=1;
if(!matchb[y]){
int z=y;
while(z){
matchb[z]=pre[z];
swap(matcha[pre[z]],z);
}
return;
}
else
q.push(matchb[y]);
}
}
}
}
ll km(){
memset(matcha,0,sizeof(matcha));
memset(matchb,0,sizeof(matchb));
for(int i=1;i<=n;i++){
la[i]=-INF;
lb[i]=0;
for(int j=1;j<=n;j++)
la[i]=max(la[i],w[i][j]);
}
for(int i=1;i<=n;i++)
bfs(i);
ll ans=0;
for(int i=1;i<=n;i++)
ans+=w[matchb[i]][i];
return ans;
}
}bg;