[SMOJ1726]染色一

97 篇文章 0 订阅
16 篇文章 0 订阅

题目描述

有一个 N N列的表格,每个格子刚开始都是白色的(用数字0表示)。每轮染色是:
1、每次你选择表格中的任意一个长方形(正方形也可以认为是长方形),长方形的4条边必须是水平的或者竖直的。
2、然后给该长方形内部染成一种颜色,颜色用数字1至9表示。

总共染色9轮,每轮只使用一种颜色,每种颜色只用一次,注意:同一个格子,后染的颜色会把该格子之前染的颜色覆盖掉。
例如:
第1轮染色(用颜色2)后是:
2220
2220
2220
0000
第2轮染色(颜色7)后是:
2220
2777
2777
0000
第3轮染色(用颜色3)后是:
2230
2737
2777
0000

现在给出经过9轮染色之后的表格的各个格子的最终颜色,在最终你能看到的那些颜色当中(例如在上面例子中,最终你能看到的颜色是2,3,7),
有多少种颜色可能是第1轮染色过程中使用的颜色?

输入格式 1726.in

第一行,一个整数 N 1N10
接下来是 N N列的表格,表示经过9轮染色之后,各个格子的最终颜色,每个格子的最终颜色是0至9。

输出格式 1726.out

一个整数。

输入样例 1726.in

4
2230
2737
2777
0000

输出样例 1726.out

1

样例说明

颜色3不可能是第一轮染色使用的颜色,颜色7不可能是第一轮染色使用的颜色,只有颜色2可能是第一轮染色使用的颜色。所以输出1。


可以看到,这题的数据范围非常小,完全可以直接用搜索做,枚举可能的颜色并判断即可。

判断这里有点小问题。直接判断某种颜色是否可能为第一种颜色是不容易写的,不妨换个角度考虑。其实可以采用排除法,对于某两种颜色,如果在一种颜色 i 的范围内出现了另一种颜色 j ,那么显然颜色 j 覆盖了颜色 i ,可以将 j 排除掉。

为了方便,可以先预处理出每种颜色出现的位置范围。总的时间复杂度为 O(n4)

参考代码:

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 10 + 5;

int n;
char a[maxn][maxn];
int minx[maxn], maxx[maxn], miny[maxn], maxy[maxn];
bool f[maxn];

bool check(int n1, int n2) {
    for (int i = minx[n1]; i <= maxx[n1]; i++)
        for (int j = miny[n1]; j <= maxy[n1]; j++)
            if (n2 + '0' == a[i][j]) return true;
    //printf("%d %d\n", n1, n2);
    return false;
}

int main(void) {
    freopen("1726.in", "r", stdin);
    freopen("1726.out", "w", stdout);
    scanf("%d", &n);
    memset(minx, 0x7f, sizeof minx); memset(miny, 0x7f, sizeof miny);
    for (int i = 1; i <= n; i++) {
        scanf("%s", a[i] + 1);
        for (int j = 1; j <= n; j++) {
            int num = a[i][j] - '0'; f[num] = true;
            minx[num] = min(minx[num], i); maxx[num] = max(maxx[num], i);
            miny[num] = min(miny[num], j); maxy[num] = max(maxy[num], j);
        }
    }
    for (int i = 1; i < 10; i++)
        if (maxx[i]) {
            bool bo = true;
            for (int j = 1; j < 10 && bo; j++)
                if (i != j && maxx[j])
                    if (check(i, j)) f[j] = false;
        }
    int ans = 0;
    for (int i = 1; i < 10; i++) if (f[i]) /*printf("%d ", i), */ans += f[i];
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值