POJ 1486:二分图匹配的必须边

题目大意:给定N个矩形,以及N个数字,已知原来每个矩形上面都有一个数字,输出能够确定的矩形和数字的二元组。

这显然是一个一一对应的问题,我们可以把矩形看成左侧的点,把数字看成右侧的点,然后如果点在矩形内,就连一条边,问题变成了求这个二分图的最大匹配,以及判断每条边在最大匹配中是不是必须要选的。

判断每条边在最大匹配中是不是必须要选的办法,就是我们把这条边删去,然后从这个点开始找增广路,如果能找到,就说明这条边不是必须的,否则是必须的。

贴个代码……

#include<iostream>
#include<math.h>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;

struct Point
{
	int x,y;
};

struct Rect
{
	int xmin, xmax, ymin, ymax;
	bool in_rect(const Point &p)
	{
		if(xmin < p.x && p.x < xmax && ymin < p.y && p.y < ymax)
		{
			return true;
		}
		return false;
	}
};

Rect rect[500];
Point point[500];
int n;

int v1, v2;
int map[500][500];
int match[500];
int ori_match[500];
bool used[500];

pair<int, int> ans[500];
int p_ans=0;

void init()
{
	memset(map, 0, sizeof(map));
	p_ans=0;
	return;
}

bool DFS(int v)
{
	used[v] = true;
	for(int i=v1+1; i<=v1+v2; i++)
	{
		if(map[v][i]==1)
		{
			int w = match[i];
			if(w==-1 || (used[w]==0 && DFS(w)==true) )
			{
				match[v] = i;
				match[i] = v;
				return true;
			}
		}
	}
	return false;
}

int bit_match()
{
	int res= 0;
	memset(match, -1, sizeof(match));
	for(int v=1; v<=v1; v++)
	{
		if(match[v]==-1)
		{
			memset(used, 0, sizeof(used));
			if(DFS(v))
				res++;
		}
	}
	return res;
}

int main()
{
	int files=0;
	while(true)
	{
		scanf("%d", &n);
		if(n==0)
			break;
		init();
		files++;
		
		int i;
		for(i=1; i<=n;i++)
		{
			scanf("%d %d %d %d", &rect[i].xmin, &rect[i].xmax, &rect[i].ymin, &rect[i].ymax);
		}
		for(i=1; i<=n; i++)
		{
			scanf("%d %d", &point[i].x, &point[i].y);
		}
		
		int j;
		for(i=1; i<=n; i++)
		{
			for(j=1; j<=n; j++)
			{
				if(rect[i].in_rect(point[j]))
				{
					map[i][j+n] = 1;
					map[j+n][i] = 1;
				}
			}
		}
		
		v1=n;
		v2=n;
		bit_match();
		memcpy(ori_match, match, sizeof(match));
		
		for(i=1; i<=n;i++)
		{
			map[i][ ori_match[i] ] = 0;
			memset(used, 0, sizeof(used));
			match[i]=-1;
			match[ori_match[i]]=-1;
			if(DFS(i) == false)
			{
				p_ans++;
				ans[p_ans].first = i;
				ans[p_ans].second = ori_match[i];
			}
			map[i][ ori_match[i] ] = 1;
			memcpy(match, ori_match, sizeof(ori_match));
		}
		
		printf("Heap %d\n", files);
		if(p_ans ==0)
		{
			printf("none");
		}
		else
		{
			sort(ans+1, ans+p_ans+1);
			for(i=1; i<=p_ans; i++)
			{
				printf("(%c,%d)", 'A'+ans[i].first-1, ans[i].second-n);
				if(i<p_ans)
					printf(" ");
			}
		}
		printf("\n");
		printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值