본문 바로가기
Algorithm

[Algorithm] Swift 백준 1244번

by ykr0919 2024. 5. 27.

 

 

https://www.acmicpc.net/problem/1244

 

 

문제접근 

 

 

문제가 조금 길어 보이긴 하지만 천천히 읽어보면 조건에 맞게 하나하나 구현해 주면 되는 문제임!!

 

잘 고려해주어야 하는 점은 남학생일 때와 여학생일 때 스위치를 조작하는 방식이 달라지는 점임!!

 

남학생은 자기가 받은 수의 배수이면 -> 스위치 상태 변경 (ex. 켜짐 -> 꺼짐, 꺼짐 -> 켜짐)

 

여학생은 자기가 받은 수와 같은 번호가 붙은 스위치를 중심으로 좌우 대칭이면서 가장 많은 스위치를 포함하는 구간을 찾아서, 그 구간에 속한 스위치 상태를 모두 바꿈. 

 

 

예를 들어 <그림 2>에서 여학생이 3을 받았다면, 3번 스위치를 중심으로 2번, 4번 스위치의 상태가 같고 1번, 5번 스위치의 상태가 같으므로, <그림 3>과 같이 1번부터 5번까지 스위치의 상태를 모두 바꿈. 만약 <그림 2>에서 여학생이 4를 받았다면, 3번, 5번 스위치의 상태가 서로 다르므로 4번 스위치의 상태만 바꿈.

 

주의❗️

 

정답을 출력할 때 스위치의 상태를 1번 스위치에서 시작하여 마지막 스위치까지 한 줄에 20개씩 출력해야 함!!!

 

 

정답풀이 

 

import Foundation

// 첫째 줄에는 스위치 개수가 주어진다. 스위치 개수는 100 이하인 양의 정수이다
let switchCount = Int(readLine()!)!

// 둘째 줄에는 각 스위치의 상태가 주어진다. 켜져 있으면 1, 꺼져있으면 0이라고 표시하고 사이에 빈칸이 하나씩 있다.
var switchs:[Int] = [0]
// i가 1부터로 이용하기 위해서 배열의 0번에 0을 넣어줌
let switchInput = readLine()!.split(separator: " ").map { Int(String($0))!}
switchs.append(contentsOf:switchInput)

// 셋째 줄에는 학생수가 주어진다. 학생수는 100 이하인 양의 정수이다
let studentsCount = Int(readLine()!)!

// 넷째 줄부터 마지막 줄까지 한 줄에 한 학생의 성별, 학생이 받은 수가 주어진다.
// 남학생은 1 여학생은 2
for _ in 0..<studentsCount {
    let input  = readLine()!.split(separator: " ").map { Int(String($0))!}
    let (gender, number) = (input[0], input[1])
    // 남학생이 받은 수의 배수이면 스위치 상태를 바꿈 ex3 3 6을 바꿈
    if gender == 1 {
        // 배수를 구해야 함
        for i in number..<switchs.count {
            if i % number == 0 {
                if switchs[i] == 1 {
                    switchs[i] = 0
                } else {
                    switchs[i] = 1
                }
            }
        }
    }
    // 여자부분
    else {
        // 우선 자기 스위치 부터 변화
        if switchs[number] == 1 {
            switchs[number] = 0
        } else {
            switchs[number] = 1
        }
        var j = 1
        while switchs[number-j] == switchs[number+j] {
            if switchs[number-j] == switchs[number+j] {
                if switchs[number-j] == 0 && switchs[number+j] == 0 {
                    switchs[number-j] = 1
                    switchs[number+j] = 1
                    j += 1
                } else {
                    switchs[number-j] = 0
                    switchs[number+j] = 0
                    j += 1
                }
            }
        }
    }
}
// a맨 앞 0 빼고
for i in 1...switchCount {
    print(switchs[i], terminator: " ")
      if i % 20 == 0 {
          print() // 20개마다 줄 바꿈
      }
}

 

var switchs:[Int] = [0]

let switchInput = readLine()!.split(separator: " ").map { Int(String($0))!}
switchs.append(contentsOf:switchInput)

 

우선 스위치의 상태를 넣어줄 switchs 배열의 0번에 0을 넣어주었음! 

문제를 보면 스위치 번호가 1번부터 시작하기 때문에 switchs 배열에 1번으로 사용하기 위해서임.

 

 

배열의 끝에 시퀀스의 요소를 추가합니다.라고 함.

switchs 배열이 빈 배열이 아니기 때문에 append(contentsOf:)를 사용해 배열에 추가해 주었음!!

 

 

남학생 부분! 💁‍♂️

 

for _ in 0..<studentsCount {
    let input  = readLine()!.split(separator: " ").map { Int(String($0))!}
    let (gender, number) = (input[0], input[1])
    // 남학생이 받은 수의 배수이면 스위치 상태를 바꿈 ex3 3 6을 바꿈
    if gender == 1 {
        // 배수를 구해야 함
        for i in number..<switchs.count {
            if i % number == 0 {
                if switchs[i] == 1 {
                    switchs[i] = 0
                } else {
                    switchs[i] = 1
                }
            }
        }
    }

 

gender가 1이면 남학생을 의미함!

주어진 스위치 번호부터 반복문을 이용해서 스위치 상태를 변경해 주었음!!

 

 

여학생 부분! 💁‍♀️

 

 else {
        // 우선 자기 스위치 부터 변화
        if switchs[number] == 1 {
            switchs[number] = 0
        } else {
            switchs[number] = 1
        }
        var j = 1
        while switchs[number-j] == switchs[number+j] {
            if switchs[number-j] == switchs[number+j] {
                if switchs[number-j] == 0 && switchs[number+j] == 0 {
                    switchs[number-j] = 1
                    switchs[number+j] = 1
                    j += 1
                } else {
                    switchs[number-j] = 0
                    switchs[number+j] = 0
                    j += 1
                }
            }
        }
    }
}

 

자기가 받은 수와 같은 번호가 붙은 스위치가 좌우 대칭이거나 아니더라도 자기 받은 번호의 스위치 상태가 바뀌어야 하기 때문에 우선 받은 번호의 스위치를 바꿔줌!!

 

그 후 while문을 이용해서

 

  while switchs[number-j] == switchs[number+j] {
  
  }

 

자기가 받은 수와 같은 번호가 붙은 스위치를 중심으로 좌우가 대칭이지 확인해 주었음!!

대칭이 맞다면 좌우 스위치 상태를 변경해 주었음!! 

변경될 때마다 j값을 증가시켜서 범위를 늘려갔음~

 

for i in 1...switchCount {
    print(switchs[i], terminator: " ")
      if i % 20 == 0 {
          print() // 20개마다 줄 바꿈
      }
}

 

마지막으로 switchs 배열을 20개마다 줄을 바꿔서 출력해 주었음!!

맨 처음에 배열에 0번에 0을 추가해 주었기 때문에 switchs[1] 번부터 출력을 해줌!!!

 

예시 입력을 넣어주니깐 

 

 

잘 나온다!!! 

 

 

하지만 제출을 하였을 땐 계속 런타임 에러가 떴음!!! 😂

 

 

무엇이 문제일까????? 🤔

 

  while switchs[number-j] == switchs[number+j] {
  
  }

 

while문을 사용할 때 배열의 범위를 벗어났기 때문임!!! 

그래서 다시 범위를 정해주었음!

 

while (number - j > 0 && number + j <= switchCount) {
     
}

 

 

switch 배열을 확인할 때 1번부터 마지막 배열까지만 확인할 수 있도록 범위를 제한해 주었음!! 

 

이제는 과연!!! 

 

 

시간초과네......😭

 

코드가 많이 지저분한 거 같았는데... 결국... 

 

그럼 코드를 다시 정리하고 다듬어 보자!! 

 

남학생 부분! 💁‍♂️

 

// 남학생이 받은 수의 배수이면 스위치 상태를 바꿈 ex3 3 6을 바꿈
    if gender == 1 {
        // 배수를 구해야 함
        for i in number..<switchs.count {
            if i % number == 0 {
                if switchs[i] == 1 {
                    switchs[i] = 0
                } else {
                    switchs[i] = 1
                }
            }
        }

 

우선 남학생이 받은 수의 배수인 스위치 위치를 찾기 위한 코드를 stride(from:through:by:)를 사용하고 삼항연산자를 사용하여 변경해 주었음!! 

 

 

시작 값부터 종료 값까지(가능한 경우 포함) 시퀀스를 지정된 양만큼 단계별로 반환합니다.라고 함!!

 

  • 매개변수
    시작
    시퀀스에 사용할 시작 값입니다. 시퀀스에 값이 포함되어 있으면 첫 번째 값은 start입니다.


    시퀀스를 제한하는 종료 값입니다. end는 stride 단계를 사용하여 시작부터 생성될 수 있는 경우에만 결과 시퀀스의 요소입니다.

    보폭
    각 반복마다 단계별로 수행할 양입니다. 긍정적인 보폭은 위쪽으로 반복됩니다. 음의 보폭은 아래쪽으로 반복됩니다.

 

만약 남학생이 받은 번호가 3이고 스위치 개수가 8개이면 

각 반복마다 3만큼 보폭을 주게 됨

 

for i in stride(from: 3, through: 8, by: 3) {
       print(i)   
 }
 // 3
 // 6

 

 if gender == 1 {
        // 남학생이 받은 수의 배수이면 스위치 상태를 바꿈
        for i in stride(from: number, through: switchCount, by: number) {
            switchs[i] = switchs[i] == 1 ? 0 : 1
        }
    }

 

이렇게 변경!! 

 

 

여학생 부분! 💁‍♀️

 

else if gender == 2 {
        // 여학생의 경우, 좌우 대칭 구간을 찾아 스위치 상태를 바꿈
        switchs[number] = switchs[number] == 1 ? 0 : 1

        var j = 1
        while (number - j > 0 && number + j <= switchCount) {
            if switchs[number - j] == switchs[number + j] {
                switchs[number - j] = switchs[number - j] == 1 ? 0 : 1
                switchs[number + j] = switchs[number + j] == 1 ? 0 : 1
                j += 1
            } else {
                break
            }
        }
    }

 

그전에는 쓸데없이 이중으로 if문을 작성했는데 지금은 한 번만 사용하고 삼항연사자를 사용했음!!

 

import Foundation

// 첫째 줄에는 스위치 개수가 주어진다. 스위치 개수는 100 이하인 양의 정수이다
let switchCount = Int(readLine()!)!

// 둘째 줄에는 각 스위치의 상태가 주어진다. 켜져 있으면 1, 꺼져있으면 0이라고 표시하고 사이에 빈칸이 하나씩 있다.
var switchs: [Int] = [0]  
// i가 1부터로 이용하기 위해서 배열의 0번에 0을 넣어줌
let switchInput = readLine()!.split(separator: " ").map { Int(String($0))! }
switchs.append(contentsOf: switchInput)

// 셋째 줄에는 학생수가 주어진다. 학생수는 100 이하인 양의 정수이다
let studentsCount = Int(readLine()!)!

// 넷째 줄부터 마지막 줄까지 한 줄에 한 학생의 성별, 학생이 받은 수가 주어진다.
// 남학생은 1 여학생은 2
for _ in 0..<studentsCount {
    let input = readLine()!.split(separator: " ").map { Int(String($0))! }
    let (gender, number) = (input[0], input[1])

    if gender == 1 {
        // 남학생이 받은 수의 배수이면 스위치 상태를 바꿈
        for i in stride(from: number, through: switchCount, by: number) {
            switchs[i] = switchs[i] == 1 ? 0 : 1
        }
    } else if gender == 2 {
        // 여학생의 경우, 좌우 대칭 구간을 찾아 스위치 상태를 바꿈
        switchs[number] = switchs[number] == 1 ? 0 : 1

        var j = 1
        while (number - j > 0 && number + j <= switchCount) {
            if switchs[number - j] == switchs[number + j] {
                switchs[number - j] = switchs[number - j] == 1 ? 0 : 1
                switchs[number + j] = switchs[number + j] == 1 ? 0 : 1
                j += 1
            } else {
                break
            }
        }
    }
}

// 스위치 상태 출력 (20개씩 줄 바꿈)
for i in 1...switchCount {
    print(switchs[i], terminator: " ")
    if i % 20 == 0 {
        print() // 20개마다 줄 바꿈
    }
}

 

위와 같이 정리를 해보았다!!

 

 

드디어 정답!!! 😭

 

 

 

배열의 범위가 넘지 않게 주의해서 설계를 해주어야 할 거 같음!!

그리고 계속 문제 구현만 집중하다 보니 코드가 지저분해지는 느낌.. ,,

최대한 간단하고 가독성이 좋게 구현할 수 있도록 고민을 많이 해봐야 할 거 같음!! 

 

 

 

 

 

참고 및 인용

 

https://developer.apple.com/documentation/swift/stride(from:through:by:)