题目描述:这里
从这里开始,我们涉及到了一个新的问题:最小割问题
首先给出一些定义(本人根据定义自己口胡的):
一个流网络中的一个割是一个边集,使得割掉这些边集后源点与汇点不连通
而最小割问题就是一个使得边集中各边容量之和最小的割
根据ford-fulkerson定理,最小割等于最大流!
基于上面的定义,我们可以来讨论这道题了:
首先,根据套路,棋盘经过黑白染色之后可以形成一个二分图,我们由源点向黑点连边,白点向汇点连边,然后由黑点向白点连边,权值为1(所有不能用的点不做考虑)
然后跑一遍最小割,用总和减去最小割即可
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> using namespace std; const int inf=0x3f3f3f3f; struct Edge { int next; int to; int val; }edge[500005]; int head[100005]; int dir[8][2]={{2,1},{1,2},{1,-2},{2,-1},{-1,-2},{-2,-1},{-1,2},{-2,1}}; bool used[2005][2005]; int dis[100005]; int cur[100005]; int cnt=1; int n,m; int st,ed; void init() { memset(head,-1,sizeof(head)); cnt=1; } void add(int l,int r,int w) { edge[cnt].next=head[l]; edge[cnt].to=r; edge[cnt].val=w; head[l]=cnt++; } bool check(int x,int y) { return (x>=1)&&(x<=n)&&(y>=1)&&(y<=n)&&(!used[x][y]); } int ide(int x) { return (x&1)?x+1:x-1; } int idx(int x,int y) { return (x-1)*n+y; } bool bfs() { memset(dis,0,sizeof(dis)); memcpy(cur,head,sizeof(head)); dis[st]=1; queue <int> M; M.push(st); while(!M.empty()) { int u=M.front(); M.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int to=edge[i].to; if(edge[i].val&&!dis[to])dis[to]=dis[u]+1,M.push(to); } } return dis[ed]; } int dfs(int x,int lim) { if(x==ed)return lim; int ret=0; for(int i=cur[x];i!=-1;i=edge[i].next) { int to=edge[i].to; if(edge[i].val&&dis[to]==dis[x]+1) { int temp=dfs(to,min(lim,edge[i].val)); if(temp) { lim-=temp; ret+=temp; edge[i].val-=temp; edge[ide(i)].val+=temp; if(!lim)break; } } cur[x]=i; } return ret; } int dinic() { int ret=0; while(bfs())ret+=dfs(st,inf); return ret; } int main() { scanf("%d%d",&n,&m); st=n*n+1,ed=n*n+2; init(); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); used[x][y]=1; } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(used[i][j])continue; if((i+j)&1) { add(st,idx(i,j),1); add(idx(i,j),st,0); for(int k=0;k<8;k++) { int x=i+dir[k][0]; int y=j+dir[k][1]; if(check(x,y))add(idx(i,j),idx(x,y),inf),add(idx(x,y),idx(i,j),0); } }else { add(idx(i,j),ed,1); add(ed,idx(i,j),0); } } } printf("%d ",n*n-m-dinic()); return 0; }