HDU 4619 Warm up 2 (二分图最小覆盖集)

本文介绍了一种利用二分图匹配算法解决水平和垂直骨牌放置重叠问题的方法,通过构建二分图并求解最小覆盖集来找到能够消除所有重叠情况的最小骨牌移除集合,进而得出最大化保留骨牌数量的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意给你两种纸牌 ,一种水平放置共有n张,一种竖直放置共有m张,他们被放在一个无限大的网格平面上。水平放置的纸牌占据点(x, y)和(x + 1 , y) , 竖直放置的纸牌占据点(x , y) 和 (x , y + 1)。水平放置的牌之间不会重叠,竖直放置的牌之间也不会重叠,但是水平放置的牌和竖直放置的牌之间可能会重叠。让你拿走一些牌,使剩下的牌之间不会重叠并且数量最多,输出剩余的最大牌数。

思路把所有水平的骨牌放到二分图左点集,竖直骨牌放在二分图右点集. 如果左(水平)骨牌i与右(竖直)骨牌j有重叠部分,那么就在左i与右j之间连一条无向边. 所以新的二分图中每条边都代表了一个重叠的坐标位置.我们必须在每个重叠的位置上选择拿掉水平骨牌或是竖直骨牌来使得所有骨牌不重叠.(其实就是在二分图的左边或右边选每条边的端点抛弃).为了使得剩下的骨牌最多,我们移除的重叠骨牌必须最少,那么这个问题就是求二分图的最小覆盖集最终n+m-最小覆盖集数= 剩下的骨牌最大数目.


#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1000+50;

struct Max_Match
{
    int n,m;
    int g[maxn][maxn];
    bool vis[maxn];
    int left[maxn];

    void init(int n,int m)
    {
        this->n=n;
        this->m=m;
        memset(left,-1,sizeof(left));
		memset(g,0,sizeof(g));
    }

    bool match(int u)
    {
        for(int v=1;v<=m;v++)
        {
            if(g[u][v] && !vis[v])
            {
                vis[v]=true;
                if(left[v]==-1 || match(left[v]))
                {
                    left[v]=u;
                    return true;
                }
            }
        }
        return false;
    }

    int solve()
    {
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(match(i)) ans++;
        }
        return ans;
    }
}MM;
int T;
int cas = 1;
struct Node
{
	int x1,y1;
	int x2,y2;
	Node(){}
	Node(int x1,int y1,int x2,int y2):x1(x1),y1(y1),x2(x2),y2(y2){}
}node1[maxn],node2[maxn];
bool check(int i,int j)
{
	if (node1[i].x1==node2[j].x1 && node1[i].y1==node2[j].y1) 
		return true;
	else if (node1[i].x1 == node2[j].x2 && node1[i].y1==node2[j].y2)
		return true;
	else if (node1[i].x2==node2[j].x1 && node1[i].y2==node2[j].y1)
		return true;
	else if (node1[i].x2==node2[j].x2 && node1[i].y2==node2[j].y2)
		return true;
	return false;
}
int main()
{
    int n,m;
	while (scanf("%d%d",&n,&m)!=EOF && n)
	{
		MM.init(n,m);
		for (int i = 1;i<=n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			node1[i]=Node(x,y,x+1,y);
		}
		for (int i = 1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			node2[i]=Node(x,y,x,y+1);
		}
		for (int i = 1;i<=n;i++)
			for (int j = 1;j<=m;j++)
			{
				if (check(i,j))
					MM.g[i][j]=1;
			}
		printf("%d\n",n+m-MM.solve());
	}
    return 0;
}

Description

  Some 1×2 dominoes are placed on a plane. Each dominoe is placed either horizontally or vertically. It's guaranteed the dominoes in the same direction are not overlapped, but horizontal and vertical dominoes may overlap with each other. You task is to remove some dominoes, so that the remaining dominoes do not overlap with each other. Now, tell me the maximum number of dominoes left on the board.
 

Input

  There are multiple input cases. 
  The first line of each case are 2 integers: n(1 <= n <= 1000), m(1 <= m <= 1000), indicating the number of horizontal and vertical dominoes. 
Then n lines follow, each line contains 2 integers x (0 <= x <= 100) and y (0 <= y <= 100), indicating the position of a horizontal dominoe. The dominoe occupies the grids of (x, y) and (x + 1, y). 
  Then m lines follow, each line contains 2 integers x (0 <= x <= 100) and y (0 <= y <= 100), indicating the position of a horizontal dominoe. The dominoe occupies the grids of (x, y) and (x, y + 1). 
  Input ends with n = 0 and m = 0.
 

Output

  For each test case, output the maximum number of remaining dominoes in a line.
 

Sample Input

2 3 0 0 0 3 0 1 1 1 1 3 4 5 0 1 0 2 3 1 2 2 0 0 1 0 2 0 4 1 3 2 0 0
 

Sample Output

4 6
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值