hdu Warm up 2( 二分图匹配)

本文介绍了一种利用二分匹配算法解决水平与竖直放置的1*2规格牌覆盖问题的方法。通过构建二分图,将水平放置的牌视为X集合,竖直放置的牌视为Y集合,并连接可能相互覆盖的牌之间的边。最终求得最大匹配数,从而得出不被覆盖的最大牌数。

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

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
题意 :  有一种1*2格的牌,能水平放,和竖直放; 给出n个水平放的牌,并且是不会重叠覆盖的,给出m个竖直的牌,也不会覆盖. 但是水平和竖直的会覆盖, 有覆盖的牌 通过丢弃一些牌 ,使得所有牌都没有被覆盖,问不被覆盖的最大的牌数.
使用二分匹配因为水平方向 任意两个牌不会覆盖 ,即两点不会相交.竖直也一样, 所以把水平看成X集合,竖直看成Y集合 . 两点连线相当于两个牌互相覆盖 . 找出这个图的最大匹配 ,每个匹配是 互相覆盖的两个牌,所以,一个匹配,即一条边,只能留一个牌,所以相当于丢弃的牌=最大匹配 .说明一下,图中不是最大匹配的边,就是独立的一张牌,所以,不用丢弃. 所以答案为 总牌数-最大匹配 .
每个牌子只给一个左边(x,y),则这个牌占的格子是(x,y)(x+1,y)或者竖直的(x,y)(x,y+1);
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> #define maxn 1010 using namespace std; int N,M; struct node {     int x,y; } p1[1010],p2[1010]; int lef[maxn]; bool T[maxn]; int cnt; vector<int> g[1010]; bool match(int u) {     int i,j;     for(i=0; i<g[u].size(); i++)     {         int v = g[u][i];         if (!T[v])         {             T[v] = true;             if (lef[v] == -1 || match(lef[v]))             {                 lef[v] = u;                 return true;             }         }     }     return false; } int solve() {     memset(lef, -1, sizeof(lef));     int ans = 0;     int u;     for(u = 1; u <= N; u++)     {         memset(T, 0, sizeof(T));         if(match(u))         {             ans++;         }     }     return ans; } bool judge(int a,int b) //判断两点是否练成一条边,即两个牌是否覆盖 {     if(p1[a].x==p2[b].x&&p1[a].y==p2[b].y)     {         return true;     }     if(p1[a].x==p2[b].x&&p1[a].y==p2[b].y+1)     {         return true;     }     if(p1[a].x+1==p2[b].x&&p1[a].y==p2[b].y)     {         return true;     }     if(p1[a].x+1==p2[b].x&&p1[a].y==p2[b].y+1)     {         return true;     }     return false; } void build() {     int i,j;     for(i=1; i<=N; i++)     {         for(j=1; j<=M; j++)         {             if(judge(i,j))             {                 g[i].push_back(j);             }         }     } } int main() {   //  freopen("input.txt","r",stdin);     int i,j;     while(scanf("%d %d",&N,&M)==2&&N+M)     {         for(i=1; i<=N; i++)         {             scanf("%d %d",&p1[i].x,&p1[i].y);             g[i].clear();         }         for(i=1; i<=M; i++)         {             scanf("%d %d",&p2[i].x,&p2[i].y);         }         build();         int temp=solve();         printf("%d\n",N+M-temp);     }     return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值