hdu 4619 二分匹配

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4619

题意:给一些水平和竖直放置的牌,相同方向上的不会重叠,但是水平和竖直的可能重叠,问:最少拿走几块能使没有重叠的(输出是最大剩余几块)?

思路:当时没有想到二分匹配,但是由于分两种牌,建图就这样建了:如果两个牌重叠,那么添加一条边,再加上源点、汇点,跑一下网络流,就好了,流量都是1。理由是如果a->b那么别的点就不可能通过源点流到汇点,含义就是把b拿掉了,就不与其他重叠了,所以这样算就是答案。。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 3000;
const int maxm = 200000;
const int INF = 0x7FFFFFF;
struct Side{
    int to,next,c;
}side[maxm];
int top,node[maxn];
void add_side(int u,int v,int c,int rc){
    side[top]=(Side){v,node[u],c};
    node[u]=top++;
    side[top]=(Side){u,node[v],rc};
    node[v]=top++;
}
int start,end,cnt,dis[maxn],gap[maxn];
int get_flow(int u,int flow){
    //printf("%d %d\n",u,flow);
    if(u==end)return flow;
    int ans=0;
    for(int i=node[u];i!=-1;i=side[i].next){
        int v=side[i].to,c=side[i].c;
        if(dis[u]>dis[v]&&c){
            int f=get_flow(v,min(flow-ans,c));
            ans+=f;
            side[i].c-=f;
            side[i^1].c+=f;
            if(ans==flow)return ans;
        }
    }
    if(!(--gap[dis[u]]))dis[start]=cnt+2;
    gap[++dis[u]]++;
    return ans;
}
struct H{int x, y;}hh[1100];
struct V{int x, y;}vv[1100];
int jiao(H a,V b){
    if(a.x==b.x&&a.y==b.y)return true;
    if(a.x==b.x&&a.y==b.y+1)return true;
    if(a.y==b.y&&a.x+1==b.x)return true;
    if(a.y==b.y+1&&a.x+1==b.x)return true;
    return false;
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m),n+m){
        top=0;
        memset(node,-1,sizeof(node));
        memset(gap,0,sizeof(gap));
        memset(dis,0,sizeof(dis));
        for(int i=0;i<n;i++)
            scanf("%d%d",&hh[i].x,&hh[i].y);
        for(int i=0;i<m;i++)
            scanf("%d%d",&vv[i].x,&vv[i].y);
        for(int i=0;i<n;i++)
            add_side(0,i+1,1,0);
        for(int i=0;i<m;i++)
            add_side(i+1+n,n+m+1,1,0);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(jiao(hh[i],vv[j]))add_side(i+1,j+n+1,1,0);
        int ans=0;
        start=0;
        end=n+m+1;
        cnt=n+m+2;
        gap[0]=cnt;
        while(dis[start]<cnt){
            ans+=get_flow(start,INF);
        }
        printf("%d\n",n+m-ans);
    }
}
坑爹的王尼玛 ~ ~ 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值