二分图
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;
}