问题描述
输入
输出
测试用例
代码
这大概是学期内的第一道正经算法题了吧,枚举所有情况很明显超时也费空间
这个题的思路就是只枚举第一行的情况,再根据第一行的情况去推理剩下行的情况。
我没记错的话在B站上是有视频讲解类似题目的,是北大的课
#include<stdio.h> //这是第三题 解谜游戏
int main()
{ //首先这道题一个最基本的点就是暴力枚举是肯定行不通的
//参考了北京大学 算法基础的熄灯问题 进行局部枚举
int w,l;
scanf("%d %d",&w,&l);
int i,r,c;
int press[18][18] = {},now[18][18] = {}; // 这样初始化即可
long long int light;
int min = 1e8;
for(r = 1; r < w + 1; r ++)
{
scanf("%lld",&light);
for(c = 1; c <= l; c ++)
{
now[r][c] = (light% 10);
light /= 10;
}
} //将每行灯的状态录入,因为灯的左右相反并没有关系,所以不多做处理
long int m = 1;
for(int p = 1; p <= l; p ++)
{
m = m * 2;
} //计算枚举第一行一共有多少种情况
for(int q = 1; q <= m; q ++)
{
int p = 0;
int sum = 0;
for(int a = 1; a < w; a ++)
for(int b = 1 ; b < l + 1;b ++) //在第一行固定的情况下,按照本行按按钮的情况和灯的情况推断下一行
press[a + 1][b]=(now[a][b] + press[a][b] + press[a - 1][b] + press[a][b - 1] + press[a][b + 1]) % 2;
for(int c = 1; c < l + 1; c ++) //最后根据前面给定的情况,判断在这种第一行的情况下,我们可不可以熄灭全部的灯
{
if((press[w][c - 1] + press[w][c] + press[w][c + 1] + press[w - 1][c]) % 2 != now[w][c])
{
p = -1;
break;
}
else
{
p = 1;
}
}
if(p == 1) //如果可以,记录这种情况下需要按按钮的次数
{
for(r = 1; r < w + 1; r ++)
for(c = 1; c < l + 1; c ++)
if(press[r][c] == 1)
{
sum = sum + 1;
}
if(min == 0)
{
min=sum;
}
if(min != 0 && min > sum)
{
min=sum;
}
}
press[1][1]++; //迭代第一行的每种状态
c = 1;
while(press[1][c] > 1)
{
press[1][c] = 0;
c ++;
press[1][c] ++;
}
}
printf("%d\n",min);
return 0;
}