枚举 编程题#1: 画家问题(Coursera 程序设计与算法 专项课程4;枚举方法:用二进制依次加1的进位方法模拟实现)

编程题#1: 画家问题

来源: POJ (http://bailian.openjudge.cn/practice/2813/)

注意: 总时间限制: 1000ms 内存限制: 65536kB

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

输入
第一行是个整数t(1≤t ≤20),表示要测试的案例数。然后是t个案例。每个案例的首行是一个整数n (1≤n ≤15),表示墙的大小。接下来的n行表示墙的初始状态。每一行包含n个字符。第i行的第j个字符表示位于位置(i,j)上的砖的颜色。“w”表示白砖,“y”表示黄砖。

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

样例输入

2
3
yyy
yyy
yyy
5
wwwww
wwwww
wwwww
wwwww
wwwww

样例输出

0
15 


程序解答:

#include <iostream>
using namespace std;

int getPaintNum(int paint[][17]){    //获得每次成功的喷涂数
    int num = 0;
    for (int i = 0; i < 16; i++){
        for (int j = 0; j < 17; j++)
            num += paint[i][j];
    }

    return num;
}

bool guessNum(int wall[][17], int paint[][17], int n){    //判断喷涂是否成功
    int c, r;

    //根据画板颜色和周围paint颜色值判断下一行paint的颜色值
    for (r = 1; r<n; r++)
        for (c = 1; c <= n; c++)
            paint[r + 1][c] = (wall[r][c] + paint[r][c] + paint[r - 1][c] + paint[r][c - 1] + paint[r][c + 1]) % 2;

    //判断最后一行能否被画成黄色   
    for (c = 1; c <= n; c++)
        if ((paint[n][c - 1] + paint[n][c] + paint[n][c + 1] + paint[n-1][c]) % 2 != wall[n][c])
            return(false);

    return(true);
}


void theLeastPaints(int wall[][17], int paint[][17], int n){    //输出最少喷涂数
    int leastNum = 16 * 17;  //最少喷涂砖块数

    int c, cTemp = 0;
    while (1){
        if (guessNum(wall, paint, n) == true){
            if (leastNum > getPaintNum(paint))
                leastNum = getPaintNum(paint);
        }

        //枚举第一行的所有情况,枚举方法:用二进制依次加1的进位方法模拟实现
        paint[1][1]++;
        c = 1;
        while (paint[1][c] > 1) {
            paint[1][c] = 0;

            c++; 
            if (c > cTemp)
                cTemp = c;

            paint[1][c]++;
        }
        if (cTemp > n)
            break;
    }

    if (leastNum == 16 * 17)
        cout << "inf" << endl;
    else
        cout << leastNum;
}

int main(){
    int wall[16][17];    //墙的颜色矩阵,行数15+1,列数15+2;1表示白色,0表示黄色,都先置0
    int paint[16][17];   //涂画矩阵,行数15+1,列数15+2;0表示不涂画,1表示涂画,都先置0

    int t;
    int n;  //墙的大小
    char c; //墙的颜色
    cin >> t;
    while (t--){
        //矩阵初始化为 0,要专门初始化!!!
        for (int i = 0; i < 16; i++){
            for (int j = 0; j < 17; j++){
                wall[i][j] = 0;
                paint[i][j] = 0;
            }
        }

        cin >> n;
        for (int i = 1; i < n+1; i++){
            for (int j = 1; j < n+1; j++){
                cin >> c;
                if (c == 'w')
                    wall[i][j] = 1;
            }
        }

        theLeastPaints(wall, paint, n);
    }

    return 0;
}

附:
听课思路总结参考
枚举的应用:熄灯问题&讨厌的青蛙:http://blog.csdn.net/qq_30258957/article/details/54884977

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值