poj 2226 匈牙利匹配 一种构图方法

11 篇文章 0 订阅

关于匈牙利算法的描述可以去看 http://blog.csdn.net/winoros/article/details/18949489


下面贴出题目的description


Muddy Fields
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 7533   Accepted: 2778

Description

Rain has pummeled the cows' field, a rectangular grid of R rows and C columns (1 <= R <= 50, 1 <= C <= 50). While good for the grass, the rain makes some patches of bare earth quite muddy. The cows, being meticulous grazers, don't want to get their hooves dirty while they eat. 

To prevent those muddy hooves, Farmer John will place a number of wooden boards over the muddy parts of the cows' field. Each of the boards is 1 unit wide, and can be any length long. Each board must be aligned parallel to one of the sides of the field. 

Farmer John wishes to minimize the number of boards needed to cover the muddy spots, some of which might require more than one board to cover. The boards may not cover any grass and deprive the cows of grazing area but they can overlap each other. 

Compute the minimum number of boards FJ requires to cover all the mud in the field.

大意就是在一个n * m的图中,有一些地方是要加上遮挡物的,遮挡物可以横着放,可以竖着放,长度不限。要求找到遮挡物放置的最小数目。


这里用到了一种构建二分图的方法,就是以原图中的边为二分图中的点,横边在一个集合中,纵边在一个集合中,而原图中的点则作为二分图中的边,用于连接两个集合中的点(原来的边)。

对该题使用上述构图法的话,那么则是那些需要遮挡物的横边和纵边为两个集合中的点。


对于题目中给出的样例(*代表方块需要被遮挡)来说就是

                                     和    

分别作为两个集合中的点(我的代码中边是从0开始标号的), 而横边和纵边相交的点就是所建二分图中的边。

那么所求便是二分图的最小顶点覆盖,可以转化为用匈牙利算法求最大匹配。

具体对边标号的方法可以看我的代码。

(对了这个题有个蛋疼的地方,就是二分图最多会有多少个点。。。我个人认为是625,就是25*25.。。。不过代码是建了500大小的数组过去的。。。)

(再P.S. 在题目的discuss里有说数组要开900多。。。我是没有理解。。。)


// by winoros 184K 16MS C++

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <cstring>
#include <numeric>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <utility>
#define max(a,b) ((a)>(b))?(a):(b)
#define min(a,b) ((a)>(b))?(b):(a)
#define rep(i,initial_n,end_n) for(int (i)=(initial_n);(i)<(end_n);i++)
#define repp(i,initial_n,end_n) for(int (i)=(initial_n);(i)<=(end_n);(i)++)
#define reep(i,initial_n,end_n) for((i)=(initial_n);(i)<(end_n);i++)
#define reepp(i,initial_n,end_n) for((i)=(initial_n);(i)<=(end_n);(i)++)
#define eps 1.0E-9
#define MAX_N 1010
#define INF 1<<30

using namespace std;

typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;

vector<int> v[500];
int pre[500];
bool flag[500];
int atlas[55][55];

bool find(int x);
int hungary(int n);

int main() {
    int n, m, cur = 0;
    char tmp;
    scanf("%d%d", &n, &m);
    getchar();
    //读入数据,并对横边标号
    rep(i, 0, n) {
        rep(j, 0, m) {
            scanf("%c", &tmp);
            if(tmp == '.') atlas[i][j] = -1;
            else if(j == 0 || atlas[i][j - 1] == -1) atlas[i][j] = cur++;
            else  atlas[i][j] = atlas[i][j - 1];
        }
        getchar();
    }
    //对纵边标号,并建二分图
    int curr = -1;
    rep(j, 0, m) {
        rep(i, 0, n) {
            if(atlas[i][j] == -1) continue;
            else if(i == 0 || atlas[i - 1][j] == -1) v[atlas[i][j]].push_back(++curr);
            else v[atlas[i][j]].push_back(curr);
        }
    }
    printf("%d\n", hungary(cur));
    return 0;
}

bool find(int x) {
    int len = v[x].size();
    rep(i, 0, len) {
        if(!flag[v[x][i]]) {
            flag[v[x][i]] = true;
            if(pre[v[x][i]] == -1 || find(pre[v[x][i]])) {
                pre[v[x][i]] = x;
                return true;
            }
        }
    }
    return false;
}

int hungary(int n) {
    int ans = 0;
    memset(pre, 255, sizeof(pre));
    rep(i, 0, n) {
        memset(flag, 0, sizeof(flag));
        if(find(i)) ans++;
    }
    return ans;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值