HDOJ 1507(二分匹配) Uncle Tom's Inherited Land

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;
	}
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值