[SWEA] 1767. 프로세서 연결하기
부분집합 (SubSet) - 백트랙킹
- 메모리 : 25,232 KB
- 실행시간 : 129 ms
- 코드길이 : 2,815 B
- 가지치기 제외하면 399 ms
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class Solution_1767_프로세서연결하기_부분집합 {
static int N, max, min, totalCnt, map[][];
static int dx[] = { -1, 1, 0, 0 };
static int dy[] = { 0, 0, -1, 1 };
static ArrayList<int[]> list;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringBuilder answer = new StringBuilder();
int T = Integer.parseInt(in.readLine());
for (int t = 1; t <= T; t++) {
N = Integer.parseInt(in.readLine());
map = new int[N][N];
list = new ArrayList<int[]>();
max = 0;
min = Integer.MAX_VALUE;
totalCnt = 0;
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(in.readLine(), " ");
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if ((i == 0 || i == N - 1 || j == 0 || j == N - 1) && map[i][j] == 1)
continue; // 가장자리 코어는 패스
// 코어 위치 리스트에 추가
if (map[i][j] == 1) {
list.add(new int[] { i, j });
totalCnt++;
}
}
}
go(0, 0);
answer.append('#').append(t).append(' ').append(min).append('\n');
} // end test-case
System.out.print(answer);
in.close();
} // end main
// 코어를 부분집합으로 백트랙킹 : 현재코어
private static void go(int index, int cCnt) {
if (totalCnt - index + cCnt < max) return; // 남은 코어수 (totalCnt-index)
if (index == totalCnt) {
int res = getLength();
if (max < cCnt) {
max = cCnt;
min = res;
} else if (max == cCnt) {
if (min > res)
min = res;
}
return;
}
int[] cur = list.get(index);
int x = cur[0];
int y = cur[1];
// 포함
for (int d = 0; d < 4; d++) {
// 현 방향으로 전선을 놓는 것이 가능한지 체크하고
if (isAvailable(x, y, d)) {
// 가능하다면 현 방향으로 전선 놓기(2)
setStatus(x, y, d, 2);
// 다음 코어로 넘어감
go(index + 1, cCnt + 1);
// 현방향으로 전선 놓았던거 되돌리기(0)
setStatus(x, y, d, 0);
}
}
// 비포함
go(index + 1, cCnt);
}
private static boolean isAvailable(int x, int y, int d) {
int nx = x, ny = y;
while (true) {
nx += dx[d];
ny += dy[d];
if (nx < 0 || nx >= N || ny < 0 || ny >= N)
break;
if (map[nx][ny] >= 1)
return false;
}
return true;
}
private static void setStatus(int x, int y, int d, int s) {
int nx = x, ny = y;
while (true) {
nx += dx[d];
ny += dy[d];
if (nx < 0 || nx >= N || ny < 0 || ny >= N)
break;
map[nx][ny] = s;
}
}
private static int getLength() {
int lCnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] == 2)
++lCnt;
}
}
return lCnt;
}
}
조합 (Combination)
- 메모리 : 22,180 KB
- 실행시간 : 143 ms
- 코드길이 : 2,785 B
- 가지치기 제외하면 414 ms
- 원래는 조합이 더 빨라야하는데 부분집합이 더 빠른 실행속도가 나왔다…
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
public class Solution_1767_프로세서연결하기_조합 {
static int N, max, min, totalCnt, map[][];
static int dx[] = { -1, 1, 0, 0 };
static int dy[] = { 0, 0, -1, 1 };
static ArrayList<int[]> list;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
StringBuilder answer = new StringBuilder();
int T = Integer.parseInt(in.readLine());
for (int t = 1; t <= T; t++) {
N = Integer.parseInt(in.readLine());
map = new int[N][N];
list = new ArrayList<int[]>();
max = 0;
min = Integer.MAX_VALUE;
totalCnt = 0;
for (int i = 0; i < N; i++) {
StringTokenizer st = new StringTokenizer(in.readLine(), " ");
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if ((i == 0 || i == N - 1 || j == 0 || j == N - 1) && map[i][j] == 1)
continue; // 가장자리 코어는 패스
// 코어 위치 리스트에 추가
if (map[i][j] == 1) {
list.add(new int[] { i, j });
totalCnt++;
}
}
}
go(0, 0);
answer.append('#').append(t).append(' ').append(min).append('\n');
} // end test-case
System.out.print(answer);
in.close();
} // end main
// 코어를 부분집합으로 백트랙킹 : 현재코어
private static void go(int index, int cCnt) {
if (totalCnt - index + cCnt < max) return; // 남은 코어수 (totalCnt-index)
int res = getLength();
if (max < cCnt) {
max = cCnt;
min = res;
} else if (max == cCnt) {
if (min > res)
min = res;
}
for (int i = index; i < totalCnt; i++) {
int[] cur = list.get(i);
int x = cur[0];
int y = cur[1];
// 포함
for (int d = 0; d < 4; d++) {
// 현 방향으로 전선을 놓는 것이 가능한지 체크하고
if (isAvailable(x, y, d)) {
// 가능하다면 현 방향으로 전선 놓기(2)
setStatus(x, y, d, 2);
// 다음 코어로 넘어감
go(i + 1, cCnt + 1);
// 현방향으로 전선 놓았던거 되돌리기(0)
setStatus(x, y, d, 0);
}
}
}
}
private static boolean isAvailable(int x, int y, int d) {
int nx = x, ny = y;
while (true) {
nx += dx[d];
ny += dy[d];
if (nx < 0 || nx >= N || ny < 0 || ny >= N)
break;
if (map[nx][ny] >= 1)
return false;
}
return true;
}
private static void setStatus(int x, int y, int d, int s) {
int nx = x, ny = y;
while (true) {
nx += dx[d];
ny += dy[d];
if (nx < 0 || nx >= N || ny < 0 || ny >= N)
break;
map[nx][ny] = s;
}
}
private static int getLength() {
int lCnt = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (map[i][j] == 2)
lCnt++;
}
}
return lCnt;
}
}
Leave a comment