加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

ZOJ 3548 2分匹配 Chess Board

(2011-10-08 10:23:58)
标签:

zoj

3548

2分匹配

it

分类: 图论

题目描述:

输入HWnmT,和H*W01矩阵。

让你在H*W的矩阵中找到n*m个边长为a的小正方形,相邻正方形之间的距离为b,正方形和边界的距离也是b。并且a>=b。如图:
http://s8/middle/64675f54gaec0422e9457&6903548 2分匹配 Chess Board" TITLE="ZOJ 3548 2分匹配 Chess Board" />

你可以进行如下操作:把任意一个矩形涂成黑色或者白色,花费时间为T

问你最少花费多少时间能够涂成满足上述条件的形式。

解题报告:

         首先,把H*W的图分成如下几种颜色的块:
        http://s10/middle/64675f54gaec043d53339&6903548 2分匹配 Chess Board" TITLE="ZOJ 3548 2分匹配 Chess Board" />

枚举ab,对于满足n * (a + b) + b == h && m * (a + b) + b == wab,我们一定能够涂成目标形式。设一共要涂ans个矩形。

1         扫描n*m个应该是白色的块,这些块一定要单独涂色,对于每个块,如果这个块中有一点黑色,ans++,然后扫描下一个。

2         mat[n+1][m+1]n+1*m+1b*b的小块(图中红色的块),如果ij列的块中有一个白点,就把mat[i][j]标记为1,否则为0.

3         扫描图中所有绿色的长方块,如果第i行有一个绿色的块中有白点,那么就把这一行都涂成黑色,ans++,同时把在这一行的mat[i][所有]都标记为0,表示没有白点。

4         同理,扫描图中所有灰色的长方块,如果第j列有一个灰色的块中有白点,那么就把这一列都涂成黑色,ans++,同时把在这一列的mat [所有] [j]都标记为0,表示没有白点。

5         不难证明,13,4步的涂法是必须的(应为每个块不能重复涂不同的颜色),那么,此时剩下的就是红色块了(mat[i][j]=1)的,此时问题转化成:

一次可以干掉一行的或者一列的,问最少多少次可以干完。

相信到了这里大家就明白了,二分匹配最小点覆盖求解之。

代码如下:

#include<iostream>

#include<cstring>

#include<vector>

#include<algorithm>

#include<cmath>

#include<cstdio>

using namespace std;

int h, w, n, m, t;

char str[2010][2010];

int match[300], vst[300];

int mat[300][300];

vector<int> g[300];

int find(int id)

{

    for(int i = 0; i < g[id].size(); i++) if (!vst[g[id][i]])

    {

        vst[g[id][i]] = true;

        if (match[g[id][i]] == -1 || find(match[g[id][i]]))

        {

            match[g[id][i]] = id;

            return 1;

        }

    }

    return 0;

}

int solve(int n)

{

    memset(match, -1, sizeof(match));

    int tar = 0;

    for(int i = 0; i < n; i++)

    {

        memset(vst, 0, sizeof(vst));

        tar += find(i);

    }

    return tar;

}

int main()

{

    while(scanf("%d%d%d%d%d", &h, &w, &n, &m, &t) != EOF)

    {

        for(int i = 0; i < h; i++) scanf("%s", str[i]);

        int ans = -1;

        for(int a = min(h / n, w / m); a >= 1; a--)

            for(int b = a; b >= 1; b--) if (n * (a + b) + b == h && m * (a + b) + b == w)

            {

                int tmpans = 0;

                for(int i = 0; i < n; i++) for(int j = 0; j < m; j++)

                {

                    bool flag = false;

                    for(int i2 = i * (a + b) + b; i2 < (i + 1) * (a + b); i2++)

                        for(int j2 = j * (a + b) + b; j2 < (j + 1) * (a + b); j2++)

                            if (str[i2][j2] == '0'){flag = true;goto lable;}

                    lable:

                    if (flag) tmpans++;

                }

                int l = n + 1, r = m + 1;

                memset(mat, 0, sizeof(mat));

                for(int i = 0; i < l; i++) for(int j = 0; j < r; j++)

                {

                    bool flag = false;

                    for(int i2 = i * (a + b); i2 < i * (a + b) + b; i2++)

                        for(int j2 = j * (a + b); j2 < j * (a + b) + b; j2++)

                            if (str[i2][j2] == '1')

                            {flag = true; goto lable2;}

                    lable2:

                    if (flag) mat[i][j] = 1;

                }

                for(int i = 0; i < l; i++) for(int j = 0; j < m; j++)

                {

                    bool flag = false;

                    for(int i2 = i * (a + b); i2 < (i + 1) * b + i * a; i2++)

                        for(int j2 = (j + 1) * b + j * a; j2 < (j + 1) * (a + b); j2++)

                            if (str[i2][j2] == '1')

                            {flag = true; goto lable3;}

                    lable3:

                    if (flag)

                    {

                        for(int i2 = 0; i2 < r; i2++) mat[i][i2] = 0;

                        tmpans++;

                        break;

                    }

                }

                for(int j = 0; j < r; j++) for(int i = 0; i < n; i++)

                {

                    bool flag = false;

                    for(int i2 = i * (a + b) + b; i2 < (i + 1) * (a + b); i2++)

                        for(int j2 = j * (a + b); j2 < j * (a + b) + b; j2++)

                            if (str[i2][j2] == '1')

                            {flag = true; goto lable4;}

                    lable4:

                    if (flag)

                    {

                        for(int i2 = 0; i2 < l; i2++) mat[i2][j] = 0;

                        tmpans++;

                        break;

                    }

                }

                for(int i = 0; i < l; i++)

                {

                    g[i].clear();

                    for(int j = 0; j < r; j++) if (mat[i][j])

                        g[i].push_back(j);

                }

                tmpans += solve(l);

 

                if (ans == -1 || tmpans < ans) ans = tmpans;

            }

        ans *= t;

        printf("%d\n", ans);

 

    }

         return 0;

}



0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有