最近在学习一些基础的算法,编程这种事情,只能慢慢摸索,自己多去锻炼才会取得好的效果!!
熄灯问题
问题:对于给定的一个按钮矩阵5*6,使得改变每个元素的状态之后(同时改变一个状态会使得它的周围的状态都会改变)全部的灯都为熄灭状态。(其中0代表是熄灭的,1代表是亮着的)
基本思路:
1,如果直接开始采用枚举法,则共有2^5*6要列举的,不妨选取一个局部状态,如果确定了该局部状态,后面的状态会基本定下来,首先对第一列的元素进行改变,若要使第一列的灯全部熄灭,第二列只有唯一一种解法,同时,若使第二列全部熄灭,第三列也是唯一确定的……以此类推,最后一列的状态改变使得倒数第二列全部熄灭,同时最后一列也全部熄灭,则由于第一列产生的改变是正确的,否则,重新选取一个局部状态。所以只需枚举局部状态,就可以完成了,此时有2^5需要列举。
2,在一个矩阵中,有三种情况,在角上(处理三盏灯)、边上(处理四盏灯)、内部(处理五盏灯)时,当改变他们的状态时对周边所产生的改变是不一样的,不妨在矩阵外面罩上一层,使得全部满足在内部的情况,此时,矩阵为6*8。多取的行列只需要设置为0就可以了。
3,枚举方式:将按钮矩阵的第一行看做一个二进制数,通过实现++操作实现。(从左往右)
4,选择两个数组,一个放置初始情况,另一表则表示需要进行的操作(0代表不改变,1代表改变状态)。分别为puzzle[6][8],press[6][8]。
对于给定的press的第一行取值,计算出press的其它行的值:
press[r+1][c]=(puzzle[r][c]+press[r][c-1]+press[r][c]+press[r][c+1]+press[r-1][c])%2,0<r<5,0<c<7;
5,程序实现代码:
#include<iostream>
#include<stdlib.h>
using namespace std;
int puzzle[6][8];//初始值的按钮矩阵
int press[6][8];//设置的按钮矩阵
//验证由局部状态引起的变换是不是满足条件的
bool guess(){
int r, c;
for (r = 1; r < 5; ++r)
for (c = 1; c < 7; ++c)
press[r + 1][c] = (puzzle[r][c] + press[r][c] + press[r - 1][c] + press[r][c - 1] + press[r][c + 1]) % 2;
//确定了第一行之后,剩下的行数(不包括最后一行)的状态是由puzzle数组和press数组共同掌握的。
//上一行的亮暗是由下一行决定的(相同的列),但是上一行的状态又是由上、左、右以及自己的值、是否被按下所决定的。因此上一行最终若为0.则不改变,否则改变
for (c = 1; c < 7; ++c)//判断第五行的灯能否被其余的press数组熄灭
if ((press[5][c] + press[5][c + 1] + press[5][c - 1] + press[4][c]) % 2 != puzzle[5][c])
//如果改变四个的状态所得的结果与初始状态一样,则表明已经熄灭了所有的灯;若为1时,改变奇数个状态,则表明为使得灯熄灭,此时不满足条件1!=1,返回true;
//改变偶数个状态,则表明原来的灯不变,还是亮着的,返回false,继续下一个局部状态再进行验证;若为0则改变状况刚好相反!
return false;
return true;//在这个前面加了一个else导致出错!!
}
void enumerate(){
int c;
for (c = 1; c < 7; ++c)
press[1][c] = 0;//赋值局部初始状态
//当局部状态不满足时,进行第二次猜测,模拟二进制加法方式实现枚举,需要处理进位,此时从左往右加!只对第一行做改变
while (guess() == false){
press[1][1]++;
c = 1;
while (press[1][c]>1){
press[1][c] = 0;
c++;
press[1][c]++;
}
}
return;
}
int main(){
int r, c, cases, i;
cout << "input cases : ";
cin >> cases;
for (r = 0; r < 6; ++r){
press[r][0] = press[r][7] = 0;
puzzle[r][0] = puzzle[r][7] = 0;
}
for (c = 1; c < 7; ++c){
press[0][c] = 0;
puzzle[0][c] = 0;
}
//输入数据
for (i = 1; i <= cases; ++i){
for (r = 1; r < 6; ++r){
for (c = 1; c < 7; ++c)
cin >> puzzle[r][c];
}
//}
enumerate();
//输出数据
//for (i = 0; i < cases; ++i){
cout << "puzzle #" << i << endl;
for (r = 1; r < 6; ++r){
for (c = 1; c < 7; ++c)
cout << press[r][c];
cout << endl;
}
}
return 0;
}