9509 开灯
时间限制:1000MS 内存限制:65535K
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC
Description
有16的开关分别控制16盏灯,开关排列成4*4的矩形,这些开关有这样的关系: 你改变其中一个开关的状态,与其同行和同列的开关的状态也跟着改变。先给出一个这些开关的初始状态,要求将所有的开关都打开,让所有的灯都亮起来,要求按下开关的次数最少。
输入格式
第一行输入一个整数t,表示有多少个case,每个case之间有一空行,每个case输入一个0、1组成的4*4的矩阵,0表示开关状态为关,1表示开关状态为开。
输出格式
每个case输出一行,让所有灯都亮的最少按开关数。
输入样例
1 1011 1111 1111 1011
输出样例
6
提示
分别按下(1,1),(1,3),(1,4),(4,1),(4,3),(4,4)6个开关就行了
对于
1111
1011
1111
1111
要把第二行和第二列的灯各按一次。
题解
从初始状态开始深搜,搜到灯全部亮着的状态时,更新最小步数,返回。
递归情况大概是这样
dfs(当前点,步数)
{
走到下一个灯;
if(找到状态)
{
更新最小步数;
return;
}
按一下当前的灯;
dfs(当前点,步数+1);
按一下当前的灯(和之前抵消,等于没按)
dfs(当前点,步数);
}
具体代码如下
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; char Map[5][5]; int map[5][5]; int minn; int if_ok()//判断现在状态是否为灯全开的状态 { for (int i=0; i<4; i++) for (int j=0; j<4; j++) if (map[i][j]==0) return 0; return 1; } void change()//把原本字符型的改为整形,方便修改,也可以不要这步 { for (int i=0; i<4; i++) for (int j=0; j<4; j++) map[i][j]=Map[i][j]-'0'; } void pull(int x,int y)//按一下当前的灯 { map[x][y]=1-map[x][y]; for (int i=0; i<4; i++) map[i][y]=1-map[i][y]; for (int i=0; i<4; i++) map[x][i]=1-map[x][i]; } void dfs(int x,int y,int step) { x++; if (x>=4) { y++; x=0; } if (y>=4) return;//从第一个等开始,走到最后一个结束 pull(x,y); if (if_ok()) { minn=min(minn,step+1);//更新最小步数 return ; } dfs(x,y,step+1); pull(x,y); if (if_ok()) { minn=min(minn,step); return ; } dfs(x,y,step); } int main() { int T; scanf("%d",&T); while (T--) { minn=999999999; for (int i=0; i<4; i++) scanf("%s",Map[i]); change(); dfs(-1,0,0); printf("%d ",minn); } return 0; }