题目:http://www.joyoi.cn/problem/tyvj-1035
把可放的位置作为节点,相邻的连边。
可用天然有的编号作为节点的编号。
果然只用连单向边就行了。也只需记录另一部的对应点。
注意易写错的那个地方。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,x,y,head[10005],xnt,per[10005],ans; bool vis[10005],in[10005],er[10005]; struct Node{ int next,to; }edge[20005]; void add(int x1,int y1,int x2,int y2) { int u=n*(x1-1)+y1,v=n*(x2-1)+y2; edge[++xnt].next=head[u]; edge[xnt].to=v; head[u]=xnt; } void ad(int x,int y) { if(x>1&&!er[n*(x-2)+y])add(x,y,x-1,y); if(x<n&&!er[n*x+y])add(x,y,x+1,y); if(y>1&&!er[n*(x-1)+y-1])add(x,y,x,y-1); if(y<n&&!er[n*(x-1)+y+1])add(x,y,x,y+1); } bool dfs(int a) { for(int i=head[a],v;i;i=edge[i].next) if(!vis[v=edge[i].to]) { vis[v]=1; if(!per[v]||dfs(per[v]))//////dfs(per[v]) 而不是dfs(v) { per[v]=a; return true; } } return false; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); er[n*(x-1)+y]=1; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((i+j)%2&&!er[n*(i-1)+j]) ad(i,j); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((i+j)%2&&!in[n*(i-1)+j]) { memset(vis,0,sizeof vis); int u=n*(i-1)+j; if(dfs(u))in[u]=1,ans++; } printf("%d",ans); return 0; }