poj-2446

// 1856K    797MS   G++
#include <stdio.h>
#include <string.h>

#define MAX 35
#define GRID_MAX MAX*MAX
int G[MAX][MAX];
char G_relation[GRID_MAX][GRID_MAX];

int M; // length
int N; // height
int K;
int validGridNum;

int V1[GRID_MAX];
int V2[GRID_MAX];

char waittingMove[GRID_MAX];

char getPair(int curId) {
    for (int i = 1; i <= validGridNum; i++) {
        if (G_relation[curId][i]) { // if curId connect i
            if (!V2[i]) {   // if i not assigned yet
                V1[curId] = i;
                V2[i] = curId;
                return 1;
            } else {
                if (!waittingMove[V2[i]]) { // if i's owner do not waitting move
                    waittingMove[V2[i]] = 1; // try to move, waiting
                    if (getPair(V2[i])) {
                        V1[curId] = i;
                        V2[i] = curId;
                        return 1;
                    }
                }
            }
        }
    }
    return 0;
}

void solve() {
    validGridNum = N*M - K;
    int gridId = 1;
    for (int j = 0; j < N; j++) { // y
        for (int i = 0; i < M; i++) { // x
            if (G[i][j] != -1) {
                G[i][j] = gridId++;
                // printf("%d %d %d\n", i, j, G[i][j]);
            }
        }
    }

    // for (int j = 0; j < N; j++) {
    //     for (int i = 0; i< M; i++) {
    //         printf("%d ", G[i][j]);
    //     }
    //     printf("\n");
    // }

    for (int i = 0; i < M; i++) { //x 
        for (int j = 0; j < N; j++) { //y
            int curId = G[i][j];
            if (curId == -1) { // hole
                continue;
            }

            //up
            if (j < N-1) {
                int upGridId = G[i][j+1];
                if (upGridId != -1) { // upNode is not a hole
                    G_relation[curId][upGridId] = 1;
                    // printf("up %d %d\n", i, j);
                }
            }

            //down
            if (j > 0) {
                int downGridId = G[i][j-1];
                if (downGridId != -1) {
                    G_relation[curId][downGridId] = 1;
                    // printf("down %d %d\n", i, j);
                }
            }

            //left
            if (i > 0) {
                int leftGridId = G[i-1][j];
                if (leftGridId != -1) {
                    G_relation[curId][leftGridId] = 1;
                    // printf("left %d %d %d\n", i, j, G[i-1][j]);
                }
            }

            //right
            if (i < M-1) {
                int rightGridId = G[i+1][j];
                if (rightGridId != -1) {
                    G_relation[curId][rightGridId] = 1;
                    // printf("right %d %d %d\n", i, j, G[i+1][j]);
                }
            }
        }
    }

    // for (int i = 1; i <= validGridNum; i++) {
    //     for (int j = 1; j <= validGridNum; j++) {
    //         printf("%d ", G_relation[i][j]);
    //     }
    //     printf("\n");
    // }

    int maxMatch = 0;

    for (int i = 1; i <= validGridNum; i++) {
        memset(waittingMove, 0, sizeof(waittingMove));
        if (getPair(i)) {
            maxMatch++;
        }
    }
    // for (int i = 1; i <= validGridNum; i++) {
    //     printf("%d %d\n", i, V1[i]);
    // }
    // printf("%d %d\n", maxMatch, validGridNum);
    if (maxMatch == validGridNum) {
        printf("YES\n");
    } else {
        printf("NO\n");
    }
}

int main() {
    while(scanf("%d %d %d", &N, &M, &K) != EOF) {
        memset(G, 0, sizeof(G));
        memset(V1, 0, sizeof(V1));
        memset(V2, 0, sizeof(V2));
        memset(G_relation, 0, sizeof(G_relation));
        validGridNum = 0;
        for (int i = 0; i < K; i++) {
            int x;
            int y;
            scanf("%d %d", &x, &y);
            G[x-1][y-1] = -1; // a hole is -1
        }
        solve();
    }
}

用的是点复制法来建的二分图,

每个点代表board上的一个不是hole的grid,依次从左到右,从下到上的编号,

然后,每个grid和其上下左右相邻的非hole的grid之间有连接的边,

在最后判断是否能够成功时有点迷糊, 直觉上直接用最大匹配数是否等于grid个数做的判断。

但是还不能清楚的解释原因,而觉得更严谨的应该是在这些最大匹配的边里面挨个检查边的端点,看是否有 grid数量/2的边(其实就是木板)的端点 将grid全部覆盖(这样就代表这题意 ,用木板在没有重叠的情况下将grid全部覆盖).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值