http://acm.hdu.edu.cn/showproblem.php?pid=1507
思路如下:
1.读入池塘点,用mapp数组记录(0为空地,1为池塘)
2.当读入结束后,遍历所有的点,若为空地,则根据奇偶性将这些空地分别放入结构体数组ji和ou之中。(并用nj和no记录奇、偶点的数量),因为题干说了空地的数量小于等于50,所以数组不用开太大。
3.双层循环,枚举奇数偶数点,判断奇数点i和偶数点j是否相邻,若相邻则g标记两点之间的边。
4.匈牙利算法
5.遍历偶数点,看linker数组标记偶数点是否有对应的奇数点与之匹配,若有,则通过oput函数按照格式输出两个点相应坐标。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Node{//
int x,y;
Node(int x=0,int y=0):x(x),y(y){}
};
Node ji[51],ou[51];//分别记录奇偶节点坐标
int m,n;
int nj,no;//根据奇偶性把节点分为奇数偶数两边
int linker[51];//记录偶数节点与之匹配的奇数节点下标
bool g[51][51],mapp[101][101],used[51];
void oput(Node a,Node b){//用于输出
printf("(%d,%d)--(%d,%d)\n",a.x,a.y,b.x,b.y);
}
void matchnodes(){//建立从奇数点到偶数点的匹配边
for(int i=0;i<nj;i++){//枚举奇数点
for(int j=0;j<no;j++){//枚举偶数点,看是否与先前的奇数点相邻
if(abs(ji[i].x-ou[j].x)+abs(ji[i].y-ou[j].y)==1){//|Δx|+|Δy|==1则表示这两个点是相邻的
g[i][j]=1;//标记边
}
}
}
}
int dfs(int u){
for(int v=0;v<no;v++){
if(g[u][v]&&!used[v]){
used[v]=1;
if(linker[v]==-1||dfs(linker[v])){
linker[v]=u;
return 1;
}
}
}
return 0;
}
int hungary(){//匈牙利算法二分匹配
int res=0;
memset(linker,-1,sizeof(linker));
for(int u=0;u<nj;u++){
memset(used,0,sizeof(used));
if(dfs(u))res++;
}
return res;
}
int main(){
int z,px,py;
while(scanf("%d%d",&m,&n)!=EOF&&m!=0&&n!=0){
memset(g,0,sizeof(g));//记录边
memset(mapp,0,sizeof(mapp));//记录水池位置
cin>>z;
while(z--){
scanf("%d%d",&px,&py);
mapp[px][py]=1;
}
nj=no=0;//nj记录奇数点数量,no记录偶数点数量
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(mapp[i][j]==0){
if((i+j)%2==1){//如果这个点是奇数点
ji[nj++]=Node(i,j); //ji记录奇数点坐标
}
else{//如果这个点是偶数点
ou[no++]=Node(i,j);//ou记录偶数点坐标
}
}
}
}
matchnodes();//匹配空地边
cout<<hungary()<<endl;
for(int i=0;i<no;i++){
if(linker[i]!=-1){
oput(ji[linker[i]],ou[i]);
}
}
cout<<endl;
}
}