372. 棋盘覆盖(最大匹配)
挺好的一题,提出了二分图一般的解题思路...
由于二分图分为左右两个不同的点集,所以保证1和0的性质.
1:即左边的点最多与右边的一个点相连.
0:即同侧的点不可能相连.
我们观察这道题。如果将棋盘染色,行列相加为奇数为黑色,偶数为白色.这样就可以讲点分成两类.
显然同色的点不可能被1*2的方格覆盖,同时每个点只能被一个1*2覆盖符合性质..
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=110,M=10010,INF=1e9; int n,m,s,t,link[M],tot=1,dx[4]={-1,1,0,0},dy[4]={0,0,1,-1},d[M]; bool vis[N][N]; struct edge{int y,v,next;}a[M<<4]; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } inline void add(int x,int y,int v) { a[++tot].y=y;a[tot].v=v;a[tot].next=link[x];link[x]=tot; a[++tot].y=x;a[tot].v=0;a[tot].next=link[y];link[y]=tot; } inline bool bfs() { queue<int>q;q.push(s); memset(d,0,sizeof(d)); d[s]=1; while(!q.empty()) { int x=q.front();q.pop(); for(int i=link[x];i;i=a[i].next) { int y=a[i].y; if(a[i].v&&!d[y]) { d[y]=d[x]+1; q.push(y); if(y==t) return true; } } } return false; } inline int dinic(int x,int flow) { if(x==t) return flow; int rest=flow,k; for(int i=link[x];i&&rest;i=a[i].next) { int y=a[i].y; if(a[i].v&&d[y]==d[x]+1) { k=dinic(y,min(rest,a[i].v)); if(!k) d[y]=0; a[i].v-=k; a[i^1].v+=k; rest-=k; } } return flow-rest; } int main() { freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=m;++i) { int x=read(),y=read(); vis[x][y]=1; } s=0;t=n*n+1; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { if(!vis[i][j]) { if((i+j)%2==0) { add(s,(i-1)*n+j,1); for(int k=0;k<4;++k) { int x=i+dx[k]; int y=j+dy[k]; if(x>=1&&x<=n&&y>=1&&y<=n&&!vis[x][y]) add((i-1)*n+j,(x-1)*n+y,1); } } else add((i-1)*n+j,t,1); } } int maxflow=0,flow; while(bfs()) while(flow=dinic(s,INF)) maxflow+=flow; printf("%d",maxflow); return 0; }