编程题#1: 画家问题
来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩。)
注意: 总时间限制: 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”。
样例输入
样例输出
思路分析:这个问题和熄灯问题比较类似,不过就是相比熄灯问题多了个数量的统计,并且还需要判断解中数量最少的;
1、定义两个全局数组,按题目要求的最大数行多加一,列多加二;
2、定义猜解函数,因为需要统计最小值,所以在非解的情况返回一个绝对比解大的数;
3、如果为解则需统计此解中所以的数量;
4、在调用函数中需要枚举完成所有解,因为是模拟二进制的进位法,所以就利用墙第一行n后面一位的进位情况来确定,枚举的结束,并在此间不断比较以寻找最小值;
代码如下:
#include<iostream>using namespace std;
char wall[16][17] = {0};
int painting[16][17] = {0};
int n;
int guess()
{
//根据第一行的状态得出后面N-1行的状态
for (int i = 1; i < n;i++)
for (int j = 1; j <=n;j++)
painting[i + 1][j] = (wall[i][j] + painting[i][j] + painting[i - 1][j] +
painting[i][j - 1] + painting[i][j + 1]) % 2;
//判断最后一行的墙是否都为黄色0,若不是,则返回一个很大的值表示此次枚举的第一行的状态不能满足把墙全部画黄
for (int j = 1; j <=n;j++)
if ((painting[n][j] + painting[n - 1][j] + painting[n][j + 1] + painting[n][j - 1]) % 2 != wall[n][j] )
return 1001;
//若此次枚举的第一行状态能满足把墙全部画黄的要求,则计算出画了多少笔,并返回它。
int steps = 0;
for (int i = 1; i <= n;i++)
for (int j = 1; j <= n; j++)
{
if (painting[i][j] == 1)
steps++;
}
return steps;
}
int enump()
{
//定义一个最小笔数变量,并初始化一个很大的值,以方便比较。
int minStep = 1001;
//定义一个临时笔数变量。
int step = 0;
//列变量
int j;
//根据二进制的进位规则,若n的后一位为1的话,则表示n位的所有组合都进行了判断。
while (painting[1][n + 1] !=1)
{
step = guess();
//寻找做少的笔数
if (step < minStep)
minStep= step;
//利用二进制进行枚举操作
painting[1][1]++;
j = 1;
//进位处理
while (painting[1][j]>1)
{
painting[1][j] = 0;
j++;
painting[1][j]++;
}
}
return minStep;
}
int main()
{
int test;
cin >> test;
int minstep;
for (int i = 0; i < test; i++)
{
//清空上一组数据,避免错误
for (int i = 0; i < 16;i++)
for (int j = 0; j < 17; j++)
{
wall[i][j] = 0;
painting[i][j] = 0;
}
//输入墙的大小yy
cin >> n;
//初始化墙,若墙为白色则为1,黄色为0
for (int i = 1; i <= n;i++)
for (int j = 1; j <= n; j++)
{
char a;
cin >> a;
wall[i][j] = (a == 'w');
}
//进行枚举
minstep=enump();
if (minstep > 1000)
cout << "inf" << endl;
else cout << minstep << endl;
}
return 0;
}