hdu1507--二分图最大匹配

题意:你大爷,哦不!你大叔继承了一块地什么的都是废话。。安静,这里说说题意,和怎么建图。

题意:这里有一块N*M的地,但是有 K 个地方,是池塘,然后输入K行(x,y),OK,现在可以出售的地必须是 1*2 大小的矩形,并且不能是池塘。。。问,在N*M的这块地上,能有多少块地可以出售,并且,要输出这些可以出售的地的坐标。

建图:那么这里其实和我之前做过的hdu4185 差不多1A。。http://blog.csdn.net/zyy173533832/article/details/12654539

那么可以预先处理一下,把N*M的地图中,是土地的按 1,2,3....编号,在这里我们需要对于每个编号,记录这个编号的土地的坐标。那么这里他说了N*M-K <= 50,那么我们接着对于每个土地,遍历四个方向,看看有木有可以组在一起变成能卖的地,然后。。。然后图就建好啦。

那么在二分匹配的过程中也要注意的是:匹配好的数量需要÷2,输出的时候也有点需要注意的,直接看代码中的解释:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

#define MAX 105

int N,M,K;
int map[MAX][MAX];
int loc[MAX/2][2];//这里是根据编号记录坐标   如第2个地的坐标 (loc[2][0] , loc[2][1]) 
int node_num; //点数,也就是土地的数量,编号的那个

struct Edge{//邻接表
    int to,next;
}edge[MAX*4];
int head[MAX/2],edge_num;

void add(int u,int v){
    edge[edge_num].to = v;
    edge[edge_num].next = head[u];
    head[u] = edge_num++;
}

int vis[4][2]={0,1,0,-1,1,0,-1,0};

void initMap(){
    node_num = 1;
    memset(map,0,sizeof(map));

    int x,y;
    while(K --){
        cin >> x >> y;
        map[x][y] = -1;//表示此地不可用,是池塘
    }

    for(int i = 1; i <= N; i ++){
        for(int j = 1; j <= M; j ++){
            if(!map[i][j]) {
                 map[i][j] = node_num++;
                 loc[node_num-1][0] = i; loc[node_num-1][1] = j;//记录坐标
            }
        }
    }

    edge_num = 0;
    memset(head,-1,sizeof(head));
    for(int i = 1; i <= N; i ++){
        for(int j = 1; j <= M; j ++){
            if(map[i][j] != -1){
                for(int k = 0; k < 4; k ++)
                {
                    int x = i+vis[k][0],y = j+vis[k][1];
                    if(map[x][y] != -1 && x >=1 && y >= 1 && x <= N && y <= M)
                    {
                        add(map[i][j],map[x][y]); add(map[x][y],map[i][j]);
                    }
                }
            }
        }
    }
}
//------------------------
bool useif[MAX/2];
int link[MAX/2];
bool dfs(int u){
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].to;
        if(!useif[v]){
            useif[v] = true;
            if(link[v] == -1 || dfs(link[v]))
            {
                link[v] = u;
                return true;
            }
        }
    }
    return false;
}
void match(){
    int ans_num = 0;
    memset(link,-1,sizeof(link));
    for(int i = 1; i <= node_num; i ++){
        memset(useif,false,sizeof(useif));
        if(dfs(i)) ans_num++;
    }

    //print
    cout << ans_num/2 <<endl;
    bool ifmatch[MAX/2]={false}; //这里是表示这个点是不是被输出过
    for(int i = 1; i <= node_num; i ++){
        if(!ifmatch[i] && link[i] != -1 && !ifmatch[link[i]]){
            ifmatch[i] = true; ifmatch[link[i]] = true;
            printf("(%d,%d)--(%d,%d)\n",loc[i][0],loc[i][1],loc[link[i]][0],loc[link[i]][1]);
        }
    }
}

int main()
{
    bool first_cas = true;//控制案例间空行
    while(cin >> N >> M)
    {
        if(!N && !M) break;
        cin >> K;
        initMap();
        if(!first_cas) cout << endl;
        match();
        first_cas = false;
    }
    return 0;
}
个人愚昧观点,欢迎指正与讨论

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值