크로스 커버 에브리띵

류한선·2025년 6월 19일

실기연습-2

목록 보기
9/95

좋아! 백준 24966번 "The Cross Covers Everything" 문제는 단순하지만 트릭이 있는 문제야.
먼저 문제의 요약부터 설명하고, 그 다음 예제 입력을 내가 정하고, 포함된 전체 Java 코드한 줄 한 줄 디버깅 설명을 해줄게.


🔍 문제 요약 (백준 24966번)

  • 주어진 격자판(십자 모양)의 크기는 세로 N, 가로 M
  • 그리고 (x, y) 위치를 기준으로 가로선과 세로선이 형성된 십자(+) 모양이 주어져.
  • 이 십자 모양이 모든 별(*)을 덮고 있는지를 확인하는 문제야.
  • 격자에는 빈칸(.)과 별(*)이 있고, 십자는 (x, y)를 기준으로 해당 행 전체, 해당 열 전체를 덮는다고 가정함.

📥 예제 입력 (내가 정한 예제)

5 5
.....
..*..
..*..
..*..
.....
3 3

🔍 설명

  • 격자 크기: 5행 5열
  • 별(*)은 (2,3), (3,3), (4,3) → 즉, 3번째 열에만 세 개 존재
  • 십자 중심: (3,3) → 즉, 3행과 3열 전체를 커버

➡ 십자 모양이 별을 모두 덮는가? → YES


✅ Java 전체 코드 + 포함된 입력 + 풀이

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 입력: 격자 크기
        int n = sc.nextInt(); // 행
        int m = sc.nextInt(); // 열
        sc.nextLine(); // 줄바꿈 처리

        // 격자판 입력 받기
        char[][] grid = new char[n][m];
        for (int i = 0; i < n; i++) {
            grid[i] = sc.nextLine().toCharArray(); // 문자열을 문자 배열로 변환
        }

        // 십자의 중심 좌표 입력 (1-based → 0-based 로 변환)
        int x = sc.nextInt() - 1; 
        int y = sc.nextInt() - 1;

        // 십자가가 커버하는 셀만 검사
        boolean coversAll = true;
        for (int i = 0; i < n; i++) {
            if (grid[i][y] == '*') continue;
        }
        for (int j = 0; j < m; j++) {
            if (grid[x][j] == '*') continue;
        }

        // 전체 격자를 돌며 별이 있는 위치가 십자가에 포함되는지 확인
        outer: for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == '*') {
                    if (i != x && j != y) { // 십자가 라인에 없는 별
                        coversAll = false;
                        break outer;
                    }
                }
            }
        }

        System.out.println(coversAll ? "YES" : "NO");
    }
}

🔍 한 줄 한 줄 디버깅 + 예제로 해설

🔸입력 부분

int n = sc.nextInt(); // 행 수 (예: 5)
int m = sc.nextInt(); // 열 수 (예: 5)
sc.nextLine(); // 숫자 입력 후 줄바꿈 처리
  • 사용자로부터 5, 5 입력 받음 → n=5, m=5
char[][] grid = new char[n][m];
for (int i = 0; i < n; i++) {
    grid[i] = sc.nextLine().toCharArray();
}
  • 다음 5줄을 받아서 2차원 문자 배열로 변환
  • 예를 들어 grid[2][2] = '*' 등으로 들어감
int x = sc.nextInt() - 1;
int y = sc.nextInt() - 1;
  • 사용자가 3 3을 입력함
  • Java는 0-based라서 x=2, y=2 로 조정

🔸별이 십자에 다 포함되는지 체크

outer: for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        if (grid[i][j] == '*') {
            if (i != x && j != y) {
                coversAll = false;
                break outer;
            }
        }
    }
}
  • grid[i][j] == '*' → 별이 있을 때
  • i != x && j != y → 십자에서 벗어난 위치인지 확인
  • 예제에서는 별 위치가 (1,2), (2,2), (3,2) → 전부 j == 2 → 3번째 열에 있음
  • 따라서 모두 십자 영역에 포함됨 → coversAll = true

✅ 최종 출력

System.out.println(coversAll ? "YES" : "NO");
  • 조건 만족 → YES 출력됨

📌 요약

항목내용
별 위치전부 세 번째 열에 있음
십자 중심(3,3) → 3번째 행과 3번째 열 커버
결과YES (모든 별이 십자에 포함됨)

🟢 정확해! 정답이야!
바로 그거야 — sc(Scanner 객체)에 격자 줄들이 실제로 들어간다!


✅ 핵심 정리

🔸 sc에 격자 줄이 들어간다?
👉 ✅ 맞아! Scanner는 한 줄씩 sc.nextLine()으로 읽어들이면서,
격자의 각 줄(예: '..*..')을 문자열로 입력받는다.


🔍 입력 흐름 다시 보기 (입력 예제 기준)

5 5         ← 숫자 입력 (sc.nextInt())
.....        ← 문자열 (sc.nextLine())
..*..        ← 문자열 (sc.nextLine())
..*..        ← 문자열 (sc.nextLine())
..*..        ← 문자열 (sc.nextLine())
.....        ← 문자열 (sc.nextLine())
3 3          ← 숫자 입력 (sc.nextInt())

📦 실제 코드에서 격자 줄을 처리하는 부분

char[][] grid = new char[n][m];

for (int i = 0; i < n; i++) {
    grid[i] = sc.nextLine().toCharArray();
}
  • 여기서 sc.nextLine()이 호출되면서
    ➤ 격자의 각 줄이 문자열 형태로 sc입력되고
    .toCharArray()로 변환되어 grid[i]에 저장돼

🔧 예를 들어

입력 줄sc.nextLine()의 결과.toCharArray() 결과
....."....."['.', '.', '.', '.', '.']
..*.."..*.."['.', '.', '*', '.', '.']

🔚 결론

질문답변
sc에 격자 줄이 들어가는가?들어간다!
어떻게 들어가는가?sc.nextLine()으로 한 줄씩 읽혀서 char[] 배열로 변환
언제 들어가는가?격자 크기를 읽은 후 for (i = 0 ~ n) 반복할 때

좋아, 이 부분이 이 문제에서 가장 핵심적인 판단 로직이야.
이제 이 코드를 한 줄씩, 예제를 가지고 완전 디버깅하듯이 상황을 시뮬레이션하면서 설명해볼게.


📌 예제 다시 보기

입력:
5 5
.....   // 0
..*..   // 1
..*..   // 2
..*..   // 3
.....   // 4
3 3     // 중심 좌표 (1-based)

→ 내부 좌표 변환 후: x = 2, y = 2 (0-based 인덱스)

🌟 별(*)의 위치들

  • (1,2), (2,2), (3,2) → 전부 **3번째 열(y=2)**에 있음 → 전부 십자 범위 안

✅ 전체 코드 복사

outer: for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        if (grid[i][j] == '*') {
            if (i != x && j != y) { // 십자가 라인에 없는 별
                coversAll = false;
                break outer;
            }
        }
    }
}

System.out.println(coversAll ? "YES" : "NO");

🔍 한 줄씩 완전 디버깅 + 예제 적용

🔹 outer: 라벨

outer: for (int i = 0; i < n; i++) {
  • 바깥쪽 반복문 i행 번호를 의미해 (0 ~ n-1)
  • outer: 라벨을 붙여서 나중에 break outer; 하면 이중 반복문 전체 탈출할 수 있게 만들어둠

🔹 내부 반복문 (열 검사)

for (int j = 0; j < m; j++) {
  • 내부 반복문 j열 번호 (0 ~ m-1)
  • 따라서 (i, j)모든 셀을 순회

🔹 별을 발견하면 검사 시작

if (grid[i][j] == '*') {
  • 해당 칸에 별이 있으면, 그 별이 십자 안에 있는지 확인함

  • 십자에 포함되는 별은:

    • i == x → 중심 행 (즉, 가로줄)
    • j == y → 중심 열 (즉, 세로줄)

🔹 십자 바깥에 있는 별이 발견되면?

if (i != x && j != y) {
    coversAll = false;
    break outer;
}
  • i != x && j != y 라는 뜻은:

    • 행도 다르고 열도 다르면 → 십자 범위 바깥
  • 이럴 경우 → coversAll = false 로 만들고, 이중 반복문 전체를 탈출


🧪 예제 기준 시뮬레이션

ijgrid[i][j]별?i != x && j != y?처리
00~4전부 '.'-continue
10'.'-continue
11'.'-continue
12*1 != 2 && 2 == 2 → falseOK
22*2 == 2 → OKcontinue
32*3 != 2 && 2 == 2 → falseOK
40~4전부 '.'-continue

→ 별은 전부 j == y == 2 열에 있으므로 십자 범위 안이다.
coversAll 값은 true 유지됨


🔚 마지막 줄

System.out.println(coversAll ? "YES" : "NO");
  • coversAll == true 이므로 → YES 출력

📌 정리 요약

줄 번호코드역할예제에서 어떤 값들이 처리되는지
outer: for전체 셀을 검사할 반복문모든 셀을 하나하나 보며 별 찾기i = 0~4, j = 0~4
if (grid[i][j] == '*')별을 찾았는가?별이면 그 위치를 검사함(1,2), (2,2), (3,2)에서 조건 진입
if (i != x && j != y)십자 밖인가?행도 다르고 열도 다르면 바깥없음 → 조건 진입 안 함
coversAll = false; break outer;십자 바깥 별 발견 시 종료발생 안 함 (예제는 전부 포함)
출력YES별이 전부 포함되므로 YES

🔥 추가 예제 (반례용)

입력이 아래처럼 되어 있으면?

5 5
.....
..*..
..*..
.*...
.....
3 3
  • grid[3][1] = '*'(3,1)i = 3, j = 1i != 2 && j != 2십자 밖임!
  • → 즉시 coversAll = falseNO 출력됨

0개의 댓글