hdu1507——Uncle Tom's Inherited Land*————————【二分图最大匹配、奇偶分离】

/*

   二分图最大匹配,同时加上奇偶分离。用匈牙利算法增广找最大匹配及相互匹配的点对

*/

题目大意:有n*m的一块儿土地遗产,现在想要卖掉,已知黑格子是池塘不能卖,白格子需要两块儿连一起才能卖,问最多能卖多少个这样的可卖土地。

/**
    划分奇偶
    二分匹配
    增广至最大匹配
*/

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXV = 110;
struct node {

    int x, y;
    node() {
        x = 0;
        y = 0;
    }
} match[MAXV][MAXV];
bool G[MAXV][MAXV], vis[MAXV][MAXV];
int f[4][2] = {{0, 1}, {0, -1}, {1, 0}, { -1, 0}};
int n, m;
bool find_AP ( int u, int v )
{

    int x, y;
    for ( int i = 0; i < 4; i++ ) {

        x = u + f[i][0];
        y = v + f[i][1];

        if ( x <= 0 || y <= 0 || x > n || y > m )//界限
            continue;

        if ( !G[x][y] && !vis[x][y] ) { //扩展的那个顶点为白格子且未曾经过

            vis[x][y] = 1;              //标记
    //如果拓展出的顶点为未盖点或该点是匹配点同时该匹配点另一侧的匹配点可继续增广
            if ( !match[x][y].x || find_AP ( match[x][y].x, match[x][y].y ) ) {

                match[x][y].x = u;      //形成匹配
                match[x][y].y = v;
                return true;
            }
        }
    }

    return false;
}
int main() {

    int k, ans, a, b;

    while ( scanf ( "%d%d", &n, &m ) != EOF && ( n + m ) ) {

        ans = 0;
        memset ( G, 0, sizeof ( G ) );
        memset ( match, 0, sizeof ( match ) );
        for ( int i = 0; i <= n; i++ ) {

            for ( int j = 0; j <= m; j++ ) {

                match[i][j].x = 0;
                match[i][j].y = 0;
            }
        }
        scanf ( "%d", &k );
        for ( int i = 0; i < k; i++ ) {

            scanf ( "%d%d", &a, &b );
            G[a][b] = 1;                    //顶点G[a][b]为黑格子
        }
        for ( int i = 1; i <= n; i++ ) {

            for ( int j = 1; j <= m; j++ ) {

                memset ( vis, 0, sizeof ( vis ) );//清空标记
                    //如果顶点i,j为白格子且i+j为奇数则从该顶点找增广路
                if ( !G[i][j] && ( ( i + j ) & 1 ) ) {
                    if ( find_AP ( i, j ) )     //如果找到增广路,即多一条匹配
                        ans++;
                }
            }
        }
        printf ( "%d\n", ans );
        for ( int i = 1; i <= n; i++ ) {

            for ( int j = 1; j <= m; j++ ) {

                if ( ! ( ( i + j ) & 1 ) ) {

                    if ( match[i][j].x != 0 )
                        printf ( "(%d,%d)--(%d,%d)\n", match[i][j].x, match[i][j].y, i, j );
                }
            }
        }
    }
    printf ( "\n" );
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值