116. 飞行员兄弟
思路:
- 通过二进制串暴力枚举所有操作情况
- 从左上到右下扫描二进制串 (当一个答案存在多种操作情况时保证优先级整体从上到下,同行从左到右打开)
- 把每次的操作坐标存放到
ArrayList<int[]> temp
中 - 特判一下每次操作结束后的结果是否符合题意
- 如果符合题意则用temp先初始化size=0的ans,如果后面存在比ans的size更小的操作情况则更新ans
- 时间复杂度:
2
16
∗
(
16
∗
7
+
16
)
2^{16}*(16*7+16)
216∗(16∗7+16)
import java.util.*;
import java.io.*;
public class Main {
Scanner s = new Scanner(System.in);
BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
char[][] g;
ArrayList<int[]> list;
String line;
public void run() throws Exception {
list = new ArrayList<>();
g = new char[4][4];
for (int i = 0; i < 4; i++) {
line = s.next();
for (int j = 0; j < 4; j++) {
g[i][j] = line.charAt(j);
}
}
minStep(g);
log.flush();
}
public void minStep(char[][] c) throws Exception {
char[][] backup = new char[4][4];
for (int i = 0; i < 4; i++)
System.arraycopy(c[i], 0, backup[i], 0, 4);
ArrayList<int[]> ans = new ArrayList<>();
for (int op = 0; op < 1 << 16; op++) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
if ((op >> get(i, j) & 1) == 1) {
turn(backup, i, j);
list.add(new int[]{i + 1, j + 1});
}
}
boolean openAll = true;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (backup[i][j] == '+') {
openAll = false;
break;
}
}
}
if (openAll) {
if (ans.isEmpty() || ans.size() > list.size()) listCopy(ans, list);
}
for (int i = 0; i < 4; i++)
System.arraycopy(c[i], 0, backup[i], 0, 4);
list.clear();
}
log.write(ans.size() + "\n");
for (int i = 0; i < ans.size(); i++) {
log.write(ans.get(i)[0] + " " + ans.get(i)[1] + "\n");
}
}
private void listCopy(ArrayList<int[]> desc, ArrayList<int[]> src) {
desc.clear();
desc.addAll(src);
}
public int get(int x, int y) {
return x * 4 + y;
}
public void turn(char[][] c, int x, int y) {
for (int i = 0; i < 4; i++) {
c[i][y] = c[i][y] == '+' ? '-' : '+';
}
for (int j = 0; j < 4; j++) {
c[x][j] = c[x][j] == '+' ? '-' : '+';
}
c[x][y] = c[x][y] == '+' ? '-' : '+';
}
public static void main(String[] args) throws Exception {
new Main().run();
}
}