【CODEVS】1922 骑士共存问题
【算法】二分图最大匹配(最大流)
【题解】按(i+j)奇偶性染色后,发现棋子跳到的地方刚好异色。
然后就是二分图了,对于每个奇点向可以跳到的地方连边,偶点不需连(可逆)。
所以题目要求转换为求二分图上最大独立集(对于每条边,至少有一个点不被选中)。
最大独立集=总点数-最小割
//代码略 //hzwer's code: #include<iostream> #include<cstdio> #include<cstring> #define INF 0x7fffffff using namespace std; int n,m,bl,wt,ans,cnt=1; bool del[201][201]; int mark[201][201]; int xx[8]={1,1,2,2,-1,-1,-2,-2}, yy[8]={2,-2,1,-1,2,-2,1,-1}; struct data{int to,next,v;}e[500001]; int head[40002],h[40002]; void insert(int u,int v,int w) { cnt++; e[cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; e[cnt].v=w; cnt++; e[cnt].to=u; e[cnt].next=head[v]; head[v]=cnt; } void build() { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(del[i][j])continue; else if(mark[i][j]<bl) { for(int k=0;k<8;k++) { int nowx=i+xx[k],nowy=j+yy[k]; if(nowx<1||nowy<1||nowx>n||nowy>n||del[nowx][nowy])continue; insert(mark[i][j],mark[nowx][nowy],INF); } insert(0,mark[i][j],1); } else insert(mark[i][j],wt,1); } bool bfs() { int q[40002],t=0,w=1,i,now; memset(h,-1,sizeof(h)); h[0]=q[0]=0; while(t<w) { now=q[t];t++; i=head[now]; while(i) { if(h[e[i].to]==-1&&e[i].v){h[e[i].to]=h[now]+1;q[w++]=e[i].to;} i=e[i].next; } } if(h[wt]==-1)return 0; return 1; } int dfs(int x,int f) { if(x==wt)return f; int i=head[x]; int w,used=0; while(i) { if(e[i].v&&h[e[i].to]==h[x]+1) { w=f-used; w=dfs(e[i].to,min(w,e[i].v)); e[i].v-=w; e[i^1].v+=w; used+=w; if(used==f)return f; } i=e[i].next; } if(!used)h[x]=-1; return used; } void dinic(){while(bfs()){ans+=dfs(0,INF);}} int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); del[x][y]=1; } bl=1,wt=(n*n+1)/2+1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((i+j)%2==0){mark[i][j]=bl;bl++;} else {mark[i][j]=wt;wt++;} build(); dinic(); printf("%d",n*n-m-ans); return 0; }