SWEA 2117번
https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5V61LqAf8DFAWu
BFS문제이다.
근데 4중 for문을 통해서 BFS 안쓰고도 풀 수 있음
집을 기준으로 탐색하는게 아니고 전체 배열을 탐색해야 하므로, 부르트포스임
일반적인 BFS탐색은 특별히 설명할 부분이 없어서 4중 for문을 기준으로 설명
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 1; k <=N + 1; k++) {
int operatingExpenses = operatingExpensesCalc(k);
int saveHomeCount = 0;
for (Coordinates cor : houseList) {
int targetX = cor.x;
int targetY = cor.y;
int distDiff = distCalc(i, j, targetX, targetY);
if (distDiff < k) {
saveHomeCount++;
}
}
if (0 <= ProfitAndLossCalc(operatingExpenses, saveHomeCount)) {
// 안전구역에 들어가는 집이 하나라도 있으면 손익계산 해서 최댓값 갱신해서 결과 찾기
result = Math.max(result, saveHomeCount);
}
}
}
}
가장 바깥에 있는 2중 for문 2개는 이 문제 특성상 발생하는 운영비용에서 이익을 계산하기 위해서는 집을 기준으로 배열을 탐색하는 것이 아닌, 집이 아닌 곳 까지 포함하여 전체 배열을 탐색해야 한다.
그러므로 하나의 기준점을 만드는 for문이다.
3번째 for문은 k
의 값을 1씩 증가한다. k
는 거리값인데, 기준점을 시작으로 k
의 범위에 들어있냐 없냐를 결정할 수 있는 범위를 계속 늘려주는 for문이된다.
다음 4번째 for문은 집의 좌표만 담긴 값을 가져와서 집을 기준으로 for문을 돈다.k
값을 거리값으로 설정했으니 이제 기준점으로 부터 모든 집과의 거리를 계산하여 해당 집이 k
거리 안에 들어오는 여부를 파악하면 우리는 결국 이익을 계산할 수 있게된다.
BFS
4중 for문
import java.util.*;
import java.io.*;
public class Solution {
static int N, M, result, maxProfit;
static int[][] map;
static List<Coordinates> houseList;
private static class Coordinates {
int x;
int y;
public Coordinates(int x, int y) {
this.x = x;
this.y = y;
}
} // End of Coordinates class
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int t = 1; t <= T; t++) {
sb.append('#').append(t).append(' ');
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
init();
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
if (map[i][j] == 1) {
houseList.add(new Coordinates(i, j));
}
}
}
solution();
sb.append(result).append('\n');
}
bw.write(sb.toString());
bw.close();
} // End of main
private static void solution() {
// 바깥 2중 for문은 기준점을 만드는 전체 배열 탐색 for문
// 각 집간의 거리를 계산해서 포함되는 집만 찾기
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
for (int k = 1; k <=N + 1; k++) {
int operatingExpenses = operatingExpensesCalc(k);
int saveHomeCount = 0;
for (Coordinates cor : houseList) {
int targetX = cor.x;
int targetY = cor.y;
int distDiff = distCalc(i, j, targetX, targetY);
if (distDiff < k) {
saveHomeCount++;
}
}
if (0 <= ProfitAndLossCalc(operatingExpenses, saveHomeCount)) {
// 안전구역에 들어가는 집이 하나라도 있으면 손익계산 해서 최댓값 갱신해서 결과 찾기
result = Math.max(result, saveHomeCount);
}
}
}
}
} // End of solution
private static int ProfitAndLossCalc(int operatingExpenses, int saveHomeCount) {
return (saveHomeCount * M) - operatingExpenses;
} // End of ProfitAndLossCalc
private static int distCalc(int x1, int y1, int x2, int y2) {
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
} // End of distCalc
private static int operatingExpensesCalc(int k) {
return k * k + (k - 1) * (k - 1);
} // End of operatingExpensesCalc
private static void init() {
map = new int[N][N];
result = 0;
houseList = new ArrayList<>();
maxProfit = -1;
} // End of init
} // End of Main class
import java.util.*;
import java.io.*;
public class Solution {
static int N, M, maxBenefit, result;
static int[][] arr;
static int[] dirX = {0, 0, -1, 1};
static int[] dirY = {-1, 1, 0, 0};
static class Coordinates {
int x;
int y;
int dist;
public Coordinates(int x, int y, int dist) {
this.x = x;
this.y = y;
this.dist = dist;
}
} // End of Coordinates class
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringBuilder sb = new StringBuilder();
StringTokenizer st;
int T = Integer.parseInt(br.readLine());
for (int t = 1; t <= T; t++) {
sb.append('#').append(t).append(' ');
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken()); // 집 하나당 지불하는 비용.
init();
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
arr[i][j] = Integer.parseInt(st.nextToken());
}
}
for (int k = 1; k <= N+1; k++) { // 방범 면적의 크기 증가.
int protectArea = preventionAreaCalc(k); // 방범 면적 계산
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
BFS(i, j, k, protectArea);
}
}
}
sb.append(result).append('\n');
}
bw.write(sb.toString());
bw.close();
} // End of main
// 어차피 K값은 BFS탐색 전에 고정됨. K는 한번만 계산하면 그 값을 활용할 수 있음
private static void BFS(int x, int y, int distLimit, int protectArea) {
boolean[][] isVisited = new boolean[N][N];
isVisited[x][y] = true;
int homeCount = 0;
if (arr[x][y] == 1) {
homeCount++;
}
Queue<Coordinates> que = new LinkedList<>();
que.offer(new Coordinates(x, y, 1));
while (!que.isEmpty()) {
Coordinates cor = que.poll();
for (int i = 0; i < 4; i++) {
int nowX = cor.x + dirX[i];
int nowY = cor.y + dirY[i];
int dist = cor.dist;
if (rangeCheck(nowX, nowY) && !isVisited[nowX][nowY] && dist < distLimit) {
isVisited[nowX][nowY] = true;
que.offer(new Coordinates(nowX, nowY, dist + 1));
if (arr[nowX][nowY] == 1) {
homeCount++;
}
}
}
}
if (benefitCalc(protectArea, homeCount) >= 0 && maxBenefit <= benefitCalc(protectArea, homeCount)) {
result = Math.max(result, homeCount);
}
} // End of BFS
private static int benefitCalc(int area, int homeCount) { // 이익을 계산하는 메소드
// 방범 면적 - 집의 개수 * M
return (homeCount * M) - area;
} // End of calc
private static int preventionAreaCalc(int K) {
return K * K + (K - 1) * (K - 1);
} // End of preventionAreaCalc
private static boolean rangeCheck(int nowX, int nowY) {
return nowX >= 0 && nowX < N && nowY >= 0 && nowY < N;
} // End of rangeCheck
private static void init() {
result = Integer.MIN_VALUE;
maxBenefit = Integer.MIN_VALUE;
arr = new int[N][N];
} // End of init
} // End of Main class