您的位置:首页 > 编程语言 > C语言/C++

C++之练习题5

2014-04-30 14:25 232 查看
5.有一个由按钮组成的矩阵,其中每 行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位 置(上边、下边、左边、右边)的灯都会改变一次。即,如果灯原来是点亮的,就会被熄灭; 如果灯原来是熄灭的,则会被点亮。

在矩阵角上的按钮改变3盏灯的状态

在矩阵边上的按钮改变4盏灯的状态

其他的按钮改变5盏灯的状态

在上图中,左边矩阵中用X标记的按钮表示被按下,右边的矩阵表示灯状态的改变,对矩阵中的每盏灯设置一个初始状态。请你按按钮,直至 每一盏等都熄灭。与一盏灯毗邻的多个按钮被按下时,一 个操作会抵消另一次操作的结果。在下图中,第2行第3、5 列的按钮都被按下,因此第2行、第4列的灯的状态就不改变

确定需要按下哪些按钮,恰好使得所有的灯都熄灭。

输入:第一行是一个正整数N,表示需要解决的案例数。每个案例由5行组成,每一行包括6 个数字。这些数字以空格隔开,可以是0或1。0 表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。

输出:对每个案例,首先输出一行,输出字符 串“PUZZLE #m”,其中m是该案例的序号。接着按照该案例的输入格式输出5行,其中的1表示需要把对应的按钮按下,0则表示不需要按对应的按钮。每个数字以一个空格隔开。

第2次按下同一个按钮时,将抵消第1次按下时所产生的结果。因此,每个按钮最多只需要按 下一次。各个按钮被按下的顺序对最终的结果没有影响对第1行中每盏点亮的灯,按下第2行对应的按钮,就可以熄灭第1行的全部灯。如此重复下去,可以熄灭第1、2、3、4行的全部灯。

适用于一行有N个按钮的办法:

一个6位二进制数的所有取值正好是64种,让该数的每一位对应于anSwitch[0]里的一个元素(anSwitch[0][5] 对应最高位,anSwitch[0][4]对应次高位….. ),那么这个二进制数的每个取值正好表示了第一行按钮的一种状态。

0 的二进制表示形式是00 0000,即代表所有按钮都不按下

63 的二进制表示形式是11 1111,即代表所有按钮都按下

5 的二进制表示形式是00 00101,即代表右数第1,3个按钮按下

如果一行有N个按钮,那么就用一个N位二进制数

枚举过程:

要写一个从二进制数到状态的转换函数:

void SwitchStatus( int n, int * pSwitch);

该函数将整数n( 0 =<n<64)的二进制表示形式对应到数组pSwitch里去

(anSwitch[0][i] 对应第i位)

void SwitchStatus( int n, int * pSwitch){

for( i = 0;i < 6 ;i ++ )

pSwitch[i] = (n >> i ) & 1;

}

保存灯的初始状态,从第一行开始依次操作按钮使得灯 按行依次熄灭

第0行的按钮状态为枚举值

第k+1行的按钮状态应和第k行的灯状态一致

最后看最后一行灯是不是全灭

要写一个让按钮起作用的函数

void ApplySwitch( int * pLights, int * pNextLights,int * pSwitchs) ;

pSwitchs 表示一行按钮的状态

pLights 表示与按钮同一行的灯的状态

pNextLights表示按钮下一行的灯的状态

本函数根据pSwitchs 所代表的按钮状态,计算这行按钮起作用后,pLights行(当前、左、右)和pNextLights行的灯的状态

不考虑按钮的上一行的灯,是因为设定pSwitchs的值的时候, 已经确保会使得上一行的灯变成全灭(或没有上一行)

void ApplySwitch( int * pLights, int * pNextLights, int * pSwitchs) {

for( int i = 0;i < 6; i ++ ) { //依次让每个按钮起作用

if( pSwitchs[i] ) {

//按钮左边的灯改变状态

if( i > 0 )

pLights[i-1] = 1 - pLights[i-1];

//按钮所在位置的灯改变状态

pLights[i] = 1 - pLights[i];

//按钮右边的灯改变状态

if( i < 5)

pLights[i+1] = 1 - pLights[i+1];

//按钮下边的灯改变状态

pNextLights[i] = 1 - pNextLights[i];

}

}

}

程序框架:

for( int n = 0; n < 64; n ++ ) { //遍历首行按钮的64种状态

1. 用输入值初始化灯状态矩阵anPuzzle;

2. 用SwitchStatus算出n所代表的第0行按钮状态;

3. for( int k = 0; k < 5; k ++ ) {//逐行让按钮起作用,并算//出下一行按钮应该是什么状态}

1用ApplySwitch让第k行按钮起作用,算出对第k+1 行灯的影响;

2 根据第k行的灯状态设置第k+1行的按钮状态;

4. 看最后一行灯是不是全灭。若全部熄灭,则找到解, 不用再试下一种状态;

#include <memory.h>

#include <string.H>

#include <iostream>

using namespace std;

int T; int anPuzzle[6][6];

int anOriPuzzle[5][6];

int anSwitch[6][6]; //按钮状态

int i,j;

void OutputResult(int t) //输出结果

{

cout << "PUZZLE #" << t << endl;

for( int i = 0;i < 5; i ++ ) {

for( int j = 0; j < 6; j ++ ) {

cout << anSwitch[i][j];

if( j < 5 ) cout << " ";

}

cout << endl;

}

}

int main() {

cin >> T;

for( int t = 0; t < T; t ++ ) {

for( i = 0;i < 5; i ++ )

for( j = 0; j < 6; j ++ )

cin >> anOriPuzzle[i][j];

for( int n = 0; n < 64; n ++ ) { //遍历首行按钮的64种状态

memcpy( anPuzzle,anOriPuzzle,sizeof(anPuzzle));

//算出n所代表的按钮状态,放到anSwitch[0]

SwitchStatus( n, anSwitch[0]);

//下面逐行让按钮起作用,并算出下一行按钮应该是什么状态,再让它们起作用……

for( int k = 0; k < 5; k ++ ) {

//算出第k行按钮起作用后的结果

ApplySwitch( anPuzzle[k],

anPuzzle[k+1],anSwitch[k]);

//第k+1行的按钮状态应和第k行的灯状态一致

memcpy( anSwitch[k+1], anPuzzle[k],sizeof(anPuzzle[k]));

}

bool bOk = true; //记录最后一行灯是不是全灭

//看最后一行灯是不是全灭

for( k = 0; k < 6; k ++ ) {

if( anPuzzle[4][k] ) {

bOk = false;

break;

}

}

if( bOk ) {

OutputResult(t+1); //输出解

break; //找到解,就不用再试下一种状态

}

} // for( int n = 0; n < 64; n ++ )

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: