二分图总结

二分图

1.二分图<->不存在奇数环<->染色法不存在矛盾

2.匈牙利算法,匹配,最大匹配,匹配点,增广路径

最大匹配<->不存在增广路径

从左边的非匹配点,沿着一条非匹配边,走到一个匹配点,再沿着一条匹配边,走到一条匹配点,最后...到一个对面的非匹配点

3.最小点覆盖,最大独立集,最小路径点覆盖,最小路径重复点覆盖

最大匹配数=最小点覆盖=总点数-最大独立集=总点数-最小路径点覆盖

二分图中最小点覆盖=最大匹配数

最大独立集:选出最多的点,使得选出的点之间没有

<->去掉最少的点,将所有边都破坏掉

<->找最小点覆盖

最小路径点覆盖:对于一个DAG(有向无环图),用最少的互不相交(点不重合)的路径覆盖所有点

二分图总结

最小路径重复点覆盖:在原图上求传递闭包后,做最小路径点覆盖

二分图总结

把原图的重复点覆盖的路径集合叫G,传递闭包图的点覆盖集合叫G‘。

对于左边的每一条路径,如果路径中的点已经被选过,就跳过这个点,即转化成了右边的一种

对于右边的每一条路径,如果有闭包边,就把它展开成有重复点的边,即转化成了左边的一种

最大团:选出最多的点,使得选出的点之间

4.最优匹配,KM算法

5.多重匹配

经典题:棋盘覆盖

将每一个1*2的方块用中间的那一个边来代替。这样原题意转化为最多能找多少个边,他们两两没有任何交点。即是一个最大匹配问题

这里注意到棋盘中的每一个点(x,y)以x+y的奇偶性二染色,这样每两个相邻的点之间的边是二分图中的一个边,转化为二分图上的最大匹配问题

即直接套用匈牙利算法模板

#include <iostream>
#include <cstring>
#include <algorithm>
#define x first
#define y second

using namespace std;
const int N = 110;
int n;
typedef pair<int, int> PII;
PII match[N][N];
bool st[N][N];
bool block[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool find(int x,int y){
    for(int i=0;i<4;i++){
        int cx=x+dx[i],cy=y+dy[i];
        if(cx<1||cx>n||cy<1||cy>n)continue;
        if(block[cx][cy])continue;
        if(!st[cx][cy]){
            st[cx][cy]=true;
           
            
            if(!match[cx][cy].x||find(match[cx][cy].x,match[cx][cy].y)){
                match[cx][cy]={x,y};
                return true;
            }  
        }
        
    }
    return false;
}
int main(){
    int t;
    cin>>n>>t;
    while(t--){
        int x,y;
        cin>>x>>y;
        block[x][y]=1;
    }
    int res=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if((i+j)%2){
                memset(st,0,sizeof st);
                if(!block[i][j]&&find(i,j))res++;
                
            }
        }
    cout<<res<<endl;
}
上一篇:Java 重写小练习


下一篇:.Java 关于继承小练习3