算法分析
递推
目标是把所有开关全部变成1
,由于当上一行的状态确定时,若上一行存在0
的状态,只能由下一行的位置去影响上一行的0
,因此可以使用递推
- 1、只要第
0
行开关的状态确定,则所有开关的状态都可以递推出来,因此枚举第一行状态的所有情况,总有32
种情况, - 2、从第
0
行递推出第1
到第4
行的状态,若当前行状态已确定,且存在一个开关是0
状态,则需要下一行的位置对开关进行切换,影响当前行开关是0
的状态 - 3、最后枚举最后一行(第
4
行)若该状态全部是1
,则表示成功,更新最小步数
时间复杂度 $O(2^5 * 25 * 5 * 500)$
2^5
表示第0
行操作的状态,25
表示最多操作的点,5
表示操作一个需要更新5
个位置的状态,500
表示有500
的样例
参考文献
算法提高课
Java 代码
import java.util.Scanner;
public class Main {
static int N = 6;
static int[][] bg = new int[N][N];
static int[][] g = new int[N][N];
static int[] dx = new int[] {0,-1,0,1,0};
static int[] dy = new int[] {-1,0,1,0,0};
static void trun(int x,int y)
{
for(int i = 0;i < 5;i ++)
{
int a = x + dx[i];
int b = y + dy[i];
if(a < 0 || a >= 5 || b < 0 || b >= 5) continue;
g[a][b] ^= 1;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
while(n -- > 0)
{
int res = 10;
for(int i = 0;i < 5;i ++)
{
String s = scan.next();
for(int j = 0;j < 5;j ++)
bg[i][j] = s.charAt(j) - '0';
}
//枚举所有情况
for(int op = 0;op < 1 << 5;op ++)
{
int cnt = 0;
//取出备份
for(int u = 0;u < 5;u ++)
for(int v = 0;v < 5;v ++)
g[u][v] = bg[u][v];
//操作第0行开关
for(int i = 0;i < 5;i ++)
if((op >> i & 1) == 1)
{
trun(0,i);
cnt ++;
}
//递推出第1到4行的状态
for(int i = 0;i < 4;i ++)
for(int j = 0;j < 5;j ++)
if(g[i][j] == 0)
{
trun(i + 1,j);
cnt ++;
}
//检查最后一行的灯是否全亮
boolean success = true;
for(int i = 0;i < 5;i ++)
if(g[4][i] == 0)
success = false;
if(success && res > cnt) res = cnt;
}
if(res > 6) res = -1;
System.out.println(res);
}
}
}
为什么去掉bg数组就错了啊?bg数组没有用啊?
因为要对你每次的图进行32次处理,你每次处理的图必须是原图,去掉了bg数组,你每次处理的图都是上次处理过的图了,那就完全错误了。
哦,原来是这样。蟹蟹大佬。
看了下,xy对偏移量写反了,虽然对最后的结果无影响。。。
都可以的hh,都枚举到就可以了
写得好,点个赞👍