zoukankan      html  css  js  c++  java
  • HUT1697 棋盘覆盖

    给定一个棋盘,有些点是被删除的,问在这种情况下最多能够在这个棋盘中放置多少1*2的多米诺骨牌。

    这题可以用二分图匹配来解决,将二维图复制出一份,将能够放置多米诺骨牌的两个相邻的点用边进行连接。如果采用邻接矩阵的话要开一个四维的数组G[x1][y1][x2][y2] 表示坐标为x1,y1 的点与x2,y2 的点之间是否放置一块多米诺骨牌。由于内存开不下,因此采用邻接表的形式来构造这些边。最后再求一个最大匹配即可。

    代码如下(两个代码只是邻接表的实现不同):

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    
    int N, M, cnt, dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
    int G[105][105], marry[10005], visit[10005];
    int head[10005];
    
    struct Node
    {
        int num, next;
        // 相对于vector多出了一个指针变量next
    }e[40005];
    
    void buildedge(int x, int y)
    {
        e[cnt].num = y;
        e[cnt].next = head[x];
        head[x] = cnt++;
        // 前插入 
    }
    
    bool judge(int x, int y)
    {
        if (x>=1&&x<=N&&y>=1&&y<=N) {
            return true;
        }    
        else {
            return false;
        }
    }
    
    bool path(int u)
    {
        for (int i = head[u]; i != 0; i = e[i].next) {
            if (!visit[e[i].num]) {
                visit[e[i].num] = 1;
                if (!marry[e[i].num] || path(marry[e[i].num])) {
                    marry[e[i].num] = u;
                    return true;
                }
            }
        }
        return false;    
    }
    
    int main()
    {
        int x, y, sum, ans;
        while (scanf("%d %d", &N, &M) == 2) {
            sum = N*N, ans = 0, cnt = 1;
            // cnt 用来标记边的编号 
            memset(marry, 0, sizeof (marry));
            memset(head, 0, sizeof (head));   // 这样已经假设0号边没有了意义
            memset(G, 0, sizeof (G));
            for (int i = 0; i < M; ++i) {
                scanf("%d %d", &x, &y);
                G[x][y] = 1;
            }
            for (int i = 1; i <= N; ++i) {
                for (int j = 1; j <= N; ++j) {
                    if (!G[i][j]) {
                        for (int k = 0; k < 4; ++k) {
                            int xx = i+dir[k][0], yy = j+dir[k][1];
                            if (judge(xx, yy) && !G[xx][yy]) {
                                buildedge((i-1)*N+j, (xx-1)*N+yy);
                                // 前者指向后者 
                            }
                        }
                    }
                }    
            }
            for (int i = 1; i <= sum; ++i) {
                memset(visit, 0, sizeof (visit));
                if (path(i)) {
                    ++ans;
                }
            }
            printf("%d\n", ans>>1);
        }
        return 0;    
    }

    ————————————————————————————————性感的分割线—-—————————————————————————————————

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    #define MAXN 105
    using namespace std;
    
    int N, M, sum, G[MAXN][MAXN], visit[10005], marry[10005];
    int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
    
    vector<int>v[10005];
    
    bool judge(int x, int y)
    {
        if (x>=1&&x<=N&&y>=1&&y<=N) {
            return true;
        }    
        else {
            return false;
        }
    }
    
    bool path(int u)
    {
        vector<int>::iterator it;
        for (it = v[u].begin(); it != v[u].end(); ++it) {
            if (visit[*it]) {  // 防止在递归过程中陷入死循环 
                continue;
            }
            else {
                visit[*it] = 1;  // 表示对该点进行了测试
                if (!marry[*it] || path(marry[*it])) {
                    marry[*it] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
        int x, y, ans;
        while (scanf("%d %d", &N, &M) == 2) {
            sum = N*N;
            ans = 0;
            memset(marry, 0, sizeof (marry));
            memset(G, 0, sizeof (G));
            for (int i = 1; i <= M; ++i) {
                scanf("%d %d", &x, &y);            
                G[x][y] = 1;
            }
            for (int i = 1; i <= N; ++i) {
                for (int j = 1; j <= N; ++j) {
                    v[(i-1)*N+j].clear(); // 清零 
                    if (!G[i][j]) { // 说明这一点没有被删除 
                        for (int k = 0; k < 4; ++k) {
                            int xx = i+dir[k][0], yy = j+dir[k][1];
                            if (judge(xx, yy) && !G[xx][yy]) { // 只有位置合法后才去查看其值 
                                v[(i-1)*N+j].push_back((xx-1)*N+yy); // 构建合理的边
                                // 将二维的点映射到一维数值上来
                            }
                        }
                    }
                } 
            }
            for (int i = 1; i <= sum; ++i) {
                memset(visit, 0, sizeof (visit));
                if (path(i)) {// path 函数就是寻找增广路径
                    ++ans;
                }
            }
            printf("%d\n", ans>>1);
        }
        return 0;    
    }
  • 相关阅读:
    shell脚本
    正则表达式和文本处理工具二
    正则表达式和文本处理工具
    Linux基础实操六
    Linux基础实操五
    caffe 试运行MNIST
    转 Windows+VS2013爆详细Caffe编译安装教程
    python一
    VS2008 C++ 调用MATLAB 2009b 生成的DLL .
    MFC抓网页
  • 原文地址:https://www.cnblogs.com/Lyush/p/2547980.html
Copyright © 2011-2022 走看看