ACWING原题链接
思路:二进制从小到大暴力递归2^16种可能的按法,找到的第一种可行的按法即答案。
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Main{
static char p[][];//开关数组,存储开关状态
static int op[][];//操作数组,表示该位置开关是否按下
static List result;//存储结果
static boolean end;//查找到第一个结果直接结束递归并输出result
public static void main(String args[]){
Scanner scan = new Scanner(System.in);
p = new char[4][4];
op = new int[4][4];
result = new LinkedList();
end = false;
for(int i = 0; i < 4;i ++) {
String s = scan.next();
p[i][0] = s.charAt(0);
p[i][1] = s.charAt(1);
p[i][2] = s.charAt(2);
p[i][3] = s.charAt(3);
}
dfs(15);
scan.close();
}
//按单个开关,将x,y的行列上的所有开关都改变状态
public static void swap(int x,int y){
for(int i = 0; i < 4;i ++){
if(p[x][i] == '-'){
p[x][i] = '+';
}else{
p[x][i] = '-';
}
if(p[i][y] == '-'){
p[i][y] = '+';
}else{
p[i][y] = '-';
}
}
if(p[x][y] == '-'){
p[x][y] = '+';
}else{
p[x][y] = '-';
}
}
public static void dfs(int index){
if(index == -1){
//用于判断所有开关是否全部打开,true为全部打开
boolean flag = true;
//按前先备份
char copy[][] = new char[4][4];
for(int i1 = 0;i1 < 4;i1 ++)
for(int j1 = 0;j1 < 4;j1 ++)
copy[i1][j1] = p[i1][j1];
//按所有开关
for(int i = 0;i < 4;i ++)
for(int j = 0;j < 4;j ++)
if(op[i][j] == 1){
String s = Math.addExact(i, 1) + " " + Math.addExact(j, 1);
result.add(s);
swap(i,j);
}
//所有开关已经按了,现在便利是否所有开关都处于打开状态,并给flag赋值
for(int i = 0;i < 4;i ++)
if(flag == true) {
for(int j = 0;j < 4;j ++)
if(p[i][j] == '+'){
flag = false;
break;
}
}else {
//只要有一个开关处于关闭状态直接结束循环
break;
}
//判断flag状态,决定输出结果还是继续递归
if(flag == true){
end = true;
System.out.println(result.size());
for(int i = 0;i < result.size();i ++) {
System.out.println(result.get(i));
}
}else {
//开关未全部打开,本次op序列不能打开全部开关,需还原开关状态,并继续递归
for(int i1 = 0;i1 < 4;i1 ++)
for(int j1 = 0;j1 < 4;j1 ++)
p[i1][j1] = copy[i1][j1];
result.clear();
}
return;
}
if(end == true) {
return;
}else {
int x = index / 4;
int y = index % 4;
op[x][y] = 0;
dfs(index - 1);
op[x][y] = 1;
dfs(index - 1);
op[x][y] = 0;
}
}
}