PTA 画家问题

有一个正方形的墙,由NN个正方形的砖组成,其中一些砖是白色的,另外一些砖是黄色的。Bob是个画家,想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i,j)个位置的砖时, 位置(i−1,j)、 (i+1,j)、(i,j−1)、(i,j+1)上的砖都会改变颜色。请你帮助Bob计算出最少需要涂画多少块砖,才能使所有砖的颜色都变成黄色。

1-1.jpg

输入格式:

第一行是一个整数n (1≤n ≤16),表示墙的大小。接下来的n行表示墙的初始状态。每一行包含n个字符。第i行的第j个字符表示位于位置(i,j)上的砖的颜色。“w”表示白砖,“y”表示黄砖。

输出格式:

一行,如果Bob能够将所有的砖都涂成黄色,则输出最少需要涂画的砖数,否则输出“inf”。

输入样例:

在这里给出一组输入。例如:

5
wwwww
wwwww
wwwww
wwwww
wwwww

输出样例:

在这里给出相应的输出。例如:

15
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll N = 2e5 + 10;
ll n, m, T;
ll ans, sum, num, idx, flag;
vector<vector<ll>> a, b, c;//因为vector便于copy,也可以使用数组和copy函数(不知道自行百度)

ll fun(ll step) {
    for (ll i = 2; i <= n; i++) {   //通过改变第i行来修改i-1的状态
        for (ll j = 1; j <= n; j++) {
            if (!c[i - 1][j]) {     //如果上一行的j是白色就修改这行的j
                step++;
                if (j - 1 > 0)c[i][j - 1] ^= 1;
                if (j + 1 <= n)c[i][j + 1] ^= 1;
                if (i != n)c[i + 1][j] ^= 1;
                c[i][j] ^= 1;
                c[i - 1][j] ^= 1;
            }
        }
    }
    for (ll i = 1; i <= n; i++) {
        if (!c[n][i])return 1e9;//因为我们通过i行改变i-1行的状态能保证i-1行能全为黄色
        //所以可以不断递推接下来的操作,最后查询最后一行的状态是否铺满
    }
    return step;
}

void dfs(ll id, ll cnt, ll limit) {
    if (cnt == limit) {
        c = b;  //将状态赋值给新的vector,防止回溯问题
        ans = min(ans, fun(cnt));   //递推状态
        return;
    }
    for (ll i = id + 1; i <= n; i++) {
        if (i - 1 > 0)b[1][i - 1] ^= 1; //转换颜色
        if (i + 1 <= n)b[1][i + 1] ^= 1;
        if (n > 1)b[2][i] ^= 1;
        b[1][i] ^= 1;
        dfs(i, cnt + 1, limit);
        if (i - 1 > 0)b[1][i - 1] ^= 1; //回溯
        if (i + 1 <= n)b[1][i + 1] ^= 1;
        if (n > 1)b[2][i] ^= 1;
        b[1][i] ^= 1;
    }
}

int main() {
    cin >> n;
    ans = 1e9;
    a.resize(n + 5);
    for (ll i = 1; i <= n; i++) {
        a[i].resize(n + 5);
        for (ll j = 1; j <= n; j++) {
            char cx;
            cin >> cx;
            if (cx == 'y')a[i][j] = 1, sum++;
            else a[i][j] = 0;
        }
    }
    if (sum == n * n)cout << 0 << endl;
    else {
        for (ll i = 1; i <= n; i++) {   //枚举第一行转换的次数
            b = a;  //当时是想将状态赋值给新的vector,防止回溯问题,但是这个好像没啥用
            dfs(0, 0, i);   //暴力枚举第一行转换次数下的各种状态
        }
        if (ans == 1e9)cout << "inf" << endl;
        else cout << ans << endl;
    }
}
/***
 *_______________#########_______________________
 *______________############_____________________
 *______________#############____________________
 *_____________##__###########___________________
 *____________###__######_#####__________________
 *____________###_#######___####_________________
 *___________###__##########_####________________
 *__________####__###########_####_______________
 *________#####___###########__#####_____________
 *_______######___###_########___#####___________
 *_______#####___###___########___######_________
 *______######___###__###########___######_______
 *_____######___####_##############__######______
 *____#######__#####################_#######_____
 *____#######__##############################____
 *___#######__######_#################_#######___
 *___#######__######_######_#########___######___
 *___#######____##__######___######_____######___
 *___#######________######____#####_____#####____
 *____######________#####_____#####_____####_____
 *_____#####________####______#####_____###______
 *______#####______;###________###______#________
 *________##_______####________####______________
 */

  • 24
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值