链接网址:http://tyvj.cn/Problem_Show.asp?id=1035
分析:那么对两个任意方格(看作结点),如果它们分属两个不同的集合的话,那么它们之间存在边的情况只有它们是相临的方格的
时候。这样一来,我们可以将矩阵中所有元素分成两个点集,相临点间存在边的关系。那么如何分这两个集合呢, 我们可以对棋
盘进行染色(黑白),黑白相间,即相临两格不同色,这样染完色,我们就可以将同种颜色的格子作为一个集合,另外一种颜色作为
一个集合,然后相临点(格子)间存在边的关系 (当然得排除挖去的部分)。这样一个二分图就建完了。
#include<iostream>
#include<cstdio>
#include<cstring>
#define max 40120
#define N 105
using namespace std;
struct edge
{
int to; //弧头结点序号
int next;//指向下一条邻接边
int w; //指权值
}edges[max];
int head[max],k,n,m,matc,flag[max],match[max],map[N][N];
int d[4][2]={0,1,-1,0,0,-1,1,0};
int Find(int u)
{
for (int i = head[u]; i != -1; i = edges[i].next)
{
int v = edges[i].to;
if(!flag[v])
{
flag[v] = 1;
if (match[v] == -1 || Find(match[v]))
{
match[v] = u;
return 1;
}
}
}
return 0;
}
void matchs()
{
matc = 0;
for (int i = 1; i <= n*n; i++)
{
memset(flag, 0, sizeof(flag));
if (Find(i)) //不用剪枝时间更短
{
matc ++ ;
}
}
}
int main()
{
int a,b,i,j,k,x1,y1;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));
memset(match, -1, sizeof(match));
int num=1;
map[1][1]=1;
for(i=2;i<=n;i++) map[1][i]=!map[1][i-1];
for(i=2;i<=n;i++)
for(j=1;j<=n;j++)
map[i][j]=!map[i-1][j];
for(i=0;i<m;i++){
cin>>x1>>y1;
map[x1][y1]=-1;
}
/*****************************
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)
cout<<map[i][j]<<" ";
cout<<endl;
}
******************************/
for(i=1;i<=n;i++){
for(j=1;j<=n;j++)
for(k=0;k<4;k++)
{
int x=i+d[k][0];
int y=j+d[k][1];
if( x>0 && x<=n && y>0 && y<=n && map[i][j]+map[x][y]==1){
edges[num].to=(x-1)*n+y;
edges[num].next=head[(i-1)*n+j];//指向下一条邻接边
head[(i-1)*n+j]=num++;
}
}
}
matchs();
printf("%d\n",matc/2);
}
return 0;
}