#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=10010;
const int maxc=110;
vector<int>e[maxn];
int map[maxc][maxc];
int vis[maxn],pre[maxn];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int find(int u)//判断增广路是否存在,匈牙利算法
{
int i,j,v;
for(i=0;i<e[u].size();i++)
{
v=e[u][i];
if(!vis[v])
{
vis[v]=1;
if(pre[v]==-1||find(pre[v]))
{
pre[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
int n,m,num;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)break;
scanf("%d",&num);
int i,j,k,a,b,x,y,x1,y1,x2,y2;
memset(map,0,sizeof(map));
for(i=0;i<num;i++)
{
scanf("%d%d",&a,&b);
map[a][b]=1;
}
for(i=1;i<=n*m;i++)
e[i].clear();
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
if(!map[i][j]&&(i+j)%2)
{
for(k=0;k<4;k++)
{
x=i+dir[k][0];
y=j+dir[k][1];
if(x<=0||y<=0||x>n||y>m||map[x][y])continue;
e[(i-1)*m+j].push_back(((x-1)*m+y));
}
}
}
}
int ans=0;
memset(pre,-1,sizeof(pre));
for(i=1;i<=n*m;i++)
{
memset(vis,0,sizeof(vis));
ans+=find(i);
}
printf("%d\n",ans);
for(i=1;i<=n*m;i++)
{
if(pre[i]==-1)continue;
if(pre[i]%m==0){x1=pre[i]/m;y1=m;}
else{x1=pre[i]/m+1;y1=pre[i]%m;}
if(i%m==0){x2=i/m;y2=m;}
else{x2=i/m+1;y2=i%m;}
printf("(%d,%d)--(%d,%d)\n",x1,y1,x2,y2);
}
printf("\n");
}
return 0;
}
/*
n*m的矩阵,标号1~n*m,则以相邻空白格的编号建边,则边表示的就是可选的1*2的格子。
分二部图:由于横纵坐标相加为奇数的点,跟它相邻的必定是横纵坐标相加为偶数的点,
且所有奇数点加相邻偶数点覆盖所有图上的点。由此我们可以从奇数点到偶数点建二部图。
最大匹配:二分图G中,找出边数最大的子图M,使得M中各条边均无公共顶点,则M为最大匹配。
所求答案ans=最大匹配数,因为所求情况必定符合匹配,因为不能有覆盖的格子,因而最大匹配数就是所求最大的1*2格数
最后pre记录的符合最大匹配的点和它的相连点,即所求边
*/
hdu 1507 Uncle Tom's Inherited Land* 最大匹配
最新推荐文章于 2020-05-01 09:50:00 发布