All :L

[SWEA/Java] 프로세서 연결하기 (1767) 본문

CODING/SWEA

[SWEA/Java] 프로세서 연결하기 (1767)

ofijwe 2024. 8. 25. 23:46
반응형

프로세서 연결하기 (1767)

1. 문제 분석

문제 개요

  • N x N 크기의 프로세서 셀(cell) 맵에서 가능한 최대 코어(core)를 연결하고, 그에 필요한 최소 전선 길이를 구하는 문제이다.

입력 형식

  • 첫 번째 줄에 테스트 케이스의 개수 T가 주어진다.
  • 각 테스트 케이스의 첫 줄에 셀의 크기 N이 주어진다.
  • 다음 N줄에 걸쳐 N x N 셀 정보가 주어진다.

출력 형식

  • 각 테스트 케이스에 대해 "#테스트케이스번호 최소 전선 길이" 형식으로 출력한다.

2. 알고리즘 종류

  • 이 문제는 백트래킹(Backtracking) 알고리즘을 사용하여 해결한다. 백트래킹을 통해 가능한 모든 코어 연결 경우를 탐색하고 최적의 해를 찾는다.

3. 주요 부분 및 코드 작성 방법

1. 입력 처리 및 초기화

  • 입력을 받아 프로세서 셀 맵을 초기화하고, 코어의 위치를 저장한다.

2. 백트래킹을 통한 코어 연결

  • 백트래킹을 사용하여 모든 코어를 가능한 방법으로 연결한다.
  • 연결된 코어의 개수와 사용된 전선의 길이를 통해 최소 전선 길이를 계산한다.

3. 결과 출력

  • 각 테스트 케이스의 결과를 출력 형식에 맞게 출력한다.

아래와 같이 주어진 코드에 대해 세분화된 설명을 추가했습니다.

4. 코드 설명

(1) 메인 함수 (main)

  • 입력 처리 및 초기화

      BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 입력을 받기 위한 BufferedReader 객체 생성
      StringBuilder sb = new StringBuilder(); // 결과 출력을 위한 StringBuilder 객체 생성
      StringTokenizer st;
    
      int T = Integer.parseInt(br.readLine()); // 테스트 케이스 수 입력 받기
    • BufferedReader 객체를 통해 입력을 처리한다.
    • StringBuilder 객체를 생성하여 결과 출력을 준비한다.
    • 테스트 케이스의 수 T를 입력받는다.
  • 테스트 케이스 반복 및 셀 정보 초기화

      for (int tc = 1; tc <= T; tc++) { // 각 테스트 케이스에 대해 반복
          N = Integer.parseInt(br.readLine()); // 셀 크기 N 입력 받기
          cell = new int[N][N]; // N x N 셀 배열 초기화
          coreList = new ArrayList<>(); // 코어 위치를 저장할 리스트 초기화
    • 각 테스트 케이스마다 셀의 크기 N을 입력받고, 셀 배열과 코어 위치 리스트를 초기화한다.
  • 셀 정보 입력 및 코어 위치 저장

      for (int r = 0; r < N; r++) { // 각 셀 정보를 입력 받기
          st = new StringTokenizer(br.readLine());
          for (int c = 0; c < N; c++) {
              cell[r][c] = Integer.parseInt(st.nextToken()); // 셀의 상태 입력 받기
              if (r < 1 || c < 1 || r >= N - 1 || c >= N - 1) continue; // 가장자리 제외
              if (cell[r][c] == 1) coreList.add(new Point(c, r)); // 코어 위치 추가
          }
      }
    • StringTokenizer를 사용하여 각 행(row)에 대한 셀 정보를 입력받는다.
    • 셀의 상태가 1인 경우, 해당 코어가 가장자리에 위치하지 않았다면 코어 리스트에 추가한다.
  • 초기 상태 설정 및 백트래킹 시작

      minWire = Integer.MAX_VALUE; // 최소 전선 길이 초기화
      maxCore = Integer.MIN_VALUE; // 최대 연결 코어 수 초기화
    
      connect(0, 0, 0); // 백트래킹 함수 호출
      sb.append("#" + tc + " " + minWire + "\n"); // 결과 저장
      }
      System.out.println(sb); // 결과 출력
    • minWiremaxCore를 초기화한다.
    • 백트래킹을 시작하여 가능한 모든 코어 연결 경우를 탐색한다.
    • 각 테스트 케이스의 결과를 StringBuilder에 저장하고 마지막에 출력한다.

(2) 코어 연결 백트래킹 함수 (connect)

  • 기저 조건 검사

      if (idx == coreList.size()) { // 모든 코어를 처리한 경우
          if (maxCore < coreCnt) { // 현재 코어 개수가 최대 코어 개수보다 큰 경우
              maxCore = coreCnt; // 최대 코어 개수 업데이트
              minWire = wireCnt; // 최소 전선 길이 업데이트
          } else if (maxCore == coreCnt) {
              minWire = Math.min(wireCnt, minWire); // 코어 개수가 같다면 최소 전선 길이 업데이트
          }
          return; // 함수 종료
      }
    • 모든 코어를 처리한 경우, 현재 코어 개수가 최대 코어 개수보다 크거나 같은지 확인하고, 최소 전선 길이를 업데이트한다.
    • 기저 조건에 해당하면 함수가 종료된다.
  • 코어 좌표 추출

      int c = coreList.get(idx).x; // 현재 코어의 열 좌표
      int r = coreList.get(idx).y; // 현재 코어의 행 좌표
    • 현재 처리할 코어의 좌표(열, 행)를 추출한다.
  • 네 방향으로 전선 연결

      for (int dir = 0; dir < 4; dir++) { // 네 방향으로 전선 연결 시도
          int count = 0; // 전선 길이 초기화
          int nc = c; // 열 좌표 초기화
          int nr = r; // 행 좌표 초기화
    
          while (true) { // 전선 연결 가능 여부 확인
              nc += dc[dir]; // 방향에 따른 열 좌표 이동
              nr += dr[dir]; // 방향에 따른 행 좌표 이동
              if (nr < 0 || nr >= N || nc < 0 || nc >= N) break; // 경계를 벗어나면 종료
    
              if (cell[nr][nc] == 1) { // 다른 코어나 전선과 겹치면 종료
                  count = 0; // 전선 길이 초기화
                  break;
              }
              count++; // 전선 길이 증가
          }
    • 네 가지 방향(상, 하, 좌, 우)에 대해 전선을 연결할 수 있는지 확인한다.
    • 전선이 다른 코어나 전선에 겹치는 경우, 해당 방향으로의 연결을 포기한다.
  • 전선 연결 및 백트래킹 호출

      int fill_c = c; // 연결된 전선의 열 좌표
      int fill_r = r; // 연결된 전선의 행 좌표
    
      for (int i = 0; i < count; i++) { // 전선을 맵에 표시
          fill_c += dc[dir];
          fill_r += dr[dir];
          cell[fill_r][fill_c] = 1; // 전선 표시
      }
    
      if (count == 0) // 전선을 연결하지 않은 경우
          connect(idx + 1, coreCnt, wireCnt); // 다음 코어 처리
      else {
          connect(idx + 1, coreCnt + 1, wireCnt + count); // 전선을 연결한 경우
    
          fill_c = c; // 전선을 다시 제거
          fill_r = r;
          for (int i = 0; i < count; i++) { 
              fill_c += dc[dir];
              fill_r += dr[dir];
              cell[fill_r][fill_c] = 0; // 전선 제거
          }
      }
    • 전선을 연결할 수 있는 경우, 전선을 셀 맵에 표시하고 다음 코어를 백트래킹 방식으로 처리한다.
    • 백트래킹 이후에는 전선을 제거하여 상태를 원래대로 되돌린다.

5. 전체 코드

package SWEA.Day0830.SWEA프로세서_연결하기;

import java.awt.*;
import java.io.*;
import java.util.*;
import java.util.List;

public class SWEA1767 {
    static int N, minWire, maxCore; // 셀의 크기, 최소 전선 길이, 최대 연결된 코어 수
    static int[][] cell; // 셀의 상태를 저장할 2차원 배열
    static List<Point> coreList; // 코어의 위치를 저장할 리스트
    static int[] dr = {-1, 1, 0, 0}; // 행 방향 이동 배열
    static int[] dc = {0, 0 ,-1, 1}; // 열 방향 이동 배열

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 입력을 받기 위한 BufferedReader 객체 생성
        StringBuilder sb = new StringBuilder(); // 결과 출력을 위한 StringBuilder 객체 생성
        StringTokenizer st;

        int T = Integer.parseInt(br.readLine()); // 테스트 케이스 수 입력 받기

        for (int tc = 1; tc <= T; tc++) { // 각 테스트 케이스에 대해 반복
            N = Integer.parseInt(br.readLine()); // 셀 크기 N 입력 받기
            cell = new int[N][N]; // N x N 셀 배열 초기화
            coreList = new ArrayList<>(); // 코어 위치를 저장할 리스트 초기화

            for (int r = 0; r < N; r++) { // 각 셀 정보를 입력 받기
                st = new StringTokenizer(br.readLine());
                for (int c = 0; c < N; c++) {
                    cell[r][c] = Integer.parseInt(st.nextToken()); // 셀의 상태 입력 받기
                    if (r < 1 || c < 1 || r >= N - 1 || c >= N - 1) continue; // 가장자리 제외
                    if (cell[r][c] == 1) coreList.add(new Point(c, r)); // 코어 위치 추가
                }
            }
            minWire = Integer.MAX_VALUE; // 최소 전선 길이 초기화
            maxCore = Integer.MIN_VALUE; // 최대 연결 코어 수 초기화

            connect

(0, 0, 0); // 백트래킹 함수 호출
            sb.append("#" + tc + " " + minWire + "\n"); // 결과 저장
        }
        System.out.println(sb); // 결과 출력
    }

    public static void connect(int idx, int coreCnt, int wireCnt) { // idx번째 코어를 처리하는 함수
        if(idx == coreList.size()) { // 모든 코어를 처리한 경우
            if(maxCore < coreCnt) { // 현재 코어 개수가 최대 코어 개수보다 큰 경우
                maxCore = coreCnt; // 최대 코어 개수 업데이트
                minWire = wireCnt; // 최소 전선 길이 업데이트
            } else if(maxCore == coreCnt) minWire = Math.min(wireCnt, minWire); // 코어 개수가 같다면 최소 전선 길이 업데이트
            return; // 함수 종료
        }
        int c = coreList.get(idx).x; // 현재 코어의 열 좌표
        int r = coreList.get(idx).y; // 현재 코어의 행 좌표

        for(int dir = 0; dir < 4; dir++) { // 네 방향으로 전선 연결 시도
            int count = 0; // 전선 길이 초기화
            int nc = c; // 열 좌표
            int nr = r; // 행 좌표

            while(true) { // 전선 연결 가능 여부 확인
                nc += dc[dir]; // 방향에 따른 열 좌표 이동
                nr += dr[dir]; // 방향에 따른 행 좌표 이동
                if(nr < 0 || nr >= N || nc < 0 || nc >= N)  break; // 경계를 벗어나면 종료

                if (cell[nr][nc] == 1) { // 다른 코어나 전선과 겹치면 종료
                    count = 0; // 전선 길이 초기화
                    break;
                }
                count++; // 전선 길이 증가
            }
            int fill_c = c; // 연결된 전선의 열 좌표
            int fill_r = r; // 연결된 전선의 행 좌표

            for(int i=0; i<count; i++) { // 전선을 맵에 표시
                fill_c += dc[dir];
                fill_r += dr[dir];
                cell[fill_r][fill_c] = 1; // 전선 표시
            }

            if(count==0) // 전선을 연결하지 않은 경우
                connect(idx+1, coreCnt, wireCnt); // 다음 코어 처리
            else {
                connect(idx+1, coreCnt+1, wireCnt+count); // 전선을 연결한 경우

                fill_c = c; // 전선을 다시 제거
                fill_r = r;
                for(int i=0; i<count; i++) { 
                    fill_c += dc[dir];
                    fill_r += dr[dir];
                    cell[fill_r][fill_c] = 0; // 전선 제거
                }
            }
        }
    }
}
반응형

'CODING > SWEA' 카테고리의 다른 글

[SWEA/Java] 나무 높이 (14510)  (0) 2024.09.12
[SWEA/Java] 디저트 카페 (2105)  (0) 2024.09.11
[SWEA/Java] 정사각형 방(1861)  (0) 2024.08.22
[SWEA/Java] 추억의 2048 게임(6190)  (0) 2024.08.22
Comments