문제

가중치 없는 방향 그래프 G가 주어졌을 때, 모든 정점 (i, j)에 대해서, i에서 j로 가는 길이가 양수인 경로가 있는지 없는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정점의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄부터 N개 줄에는 그래프의 인접 행렬이 주어진다. i번째 줄의 j번째 숫자가 1인 경우에는 i에서 j로 가는 간선이 존재한다는 뜻이고, 0인 경우는 없다는 뜻이다. i번째 줄의 i번째 숫자는 항상 0이다.

출력

총 N개의 줄에 걸쳐서 문제의 정답을 인접행렬 형식으로 출력한다. 정점 i에서 j로 가는 길이가 양수인 경로가 있으면 i번째 줄의 j번째 숫자를 1로, 없으면 0으로 출력해야 한다.

내가 푼 풀이

- 주어진 그래프를 연결리스트로 저장한다.

- DFS를 이용하여 시작점부터 이동할 수 있는 모든 정점을 탐색하고 저장한다.

- 0번째부터 n-1번째까지 반복하며 탐색한다.

- 이미 방문한 지점이라면 break를 통해 반복문을 탈출했었지만, 만약 이중으로 연결된 리스트라면 break 반복탈출은 원하는 답이 안 나온다.

- 주어진 정점의 개수가 작아서 모든 간선을 탐색하는 방법을 사용했다.

 

import Foundation

// 입력
let n = Int(readLine()!)!
var graph = [Int: [Int]]()

// 그래프 입력
for i in 0..<n {
    let input = readLine()!.split(separator: " ").map{ Int($0)! }
    for j in 0..<input.count {
        if input[j] == 1 {
            if graph[i] == nil {
                graph[i] = [j]
            } else {
                graph[i]!.append(j)
            }
        }
    }
}

// DFS
for i in 0..<n {
    var arr = Array(repeating: 0, count: n)
    var needVisitQueue = [Int]()
    if graph[i] != nil {
        needVisitQueue = graph[i]!
        while !needVisitQueue.isEmpty {
            var node = needVisitQueue.removeLast()
            if arr[node] == 1 { continue }
            
            arr[node] = 1
            if graph[node] != nil {
                needVisitQueue += graph[node]!
            }
        }
    }
    print(arr.map{ String($0) }.joined(separator: " "))
}

 

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-2012 등수 매기기 Swift  (0) 2023.07.10
BOJ-9252 LCS 2 Swift  (0) 2023.07.10
BOJ-1417 국회의원 선거 Swift  (0) 2023.07.01
BOJ-10942 팰린드롬? Swift  (0) 2023.07.01
BOJ-2206 벽 부수고 이동하기 Swift  (0) 2023.06.30

문제

다솜이는 사람의 마음을 읽을 수 있는 기계를 가지고 있다. 다솜이는 이 기계를 이용해서 2008년 4월 9일 국회의원 선거를 조작하려고 한다.

다솜이의 기계는 각 사람들이 누구를 찍을 지 미리 읽을 수 있다. 어떤 사람이 누구를 찍을 지 정했으면, 반드시 선거때 그 사람을 찍는다.

현재 형택구에 나온 국회의원 후보는 N명이다. 다솜이는 이 기계를 이용해서 그 마을의 주민 M명의 마음을 모두 읽었다.

다솜이는 기호 1번이다. 다솜이는 사람들의 마음을 읽어서 자신을 찍지 않으려는 사람을 돈으로 매수해서 국회의원에 당선이 되게 하려고 한다. 다른 모든 사람의 득표수 보다 많은 득표수를 가질 때, 그 사람이 국회의원에 당선된다.

예를 들어서, 마음을 읽은 결과 기호 1번이 5표, 기호 2번이 7표, 기호 3번이 7표 라고 한다면, 다솜이는 2번 후보를 찍으려고 하던 사람 1명과, 3번 후보를 찍으려고 하던 사람 1명을 돈으로 매수하면, 국회의원에 당선이 된다.

돈으로 매수한 사람은 반드시 다솜이를 찍는다고 가정한다.

다솜이가 매수해야하는 사람의 최솟값을 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 후보의 수 N이 주어진다. 둘째 줄부터 차례대로 기호 1번을 찍으려고 하는 사람의 수, 기호 2번을 찍으려고 하는 수, 이렇게 총 N개의 줄에 걸쳐 입력이 들어온다. N은 50보다 작거나 같은 자연수이고, 득표수는 100보다 작거나 같은 자연수이다.

출력

첫째 줄에 다솜이가 매수해야 하는 사람의 최솟값을 출력한다.

내가 푼 풀이

- 후보의 수를 다득표순으로 정렬했을때, 첫번째 원소가 다솜보다 작을때 까지 매수하면된다.

- 매수한 만큼의 수를 출력

 

import Foundation

// 입력
var N = Int(readLine()!)!
var arr = [Int]()
var cnt = 0

// 후보 입력
for i in 0..<N {
    arr.append(Int(readLine()!)!)
}

// 다솜
var ds = arr[0]
arr.removeFirst()
arr.sort { $0 > $1 }

// 후보를 다득표순으로 정렬후, 맨 첫번째 원소가 다솜보다 작을때까지 매수한다.
while !arr.isEmpty && arr[0] >= ds {
    cnt += 1
    ds += 1
    arr[0] -= 1
    arr.sort { $0 > $1 }
}

print(cnt)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-9252 LCS 2 Swift  (0) 2023.07.10
BOJ-11403 경로 찾기 Swift  (0) 2023.07.01
BOJ-10942 팰린드롬? Swift  (0) 2023.07.01
BOJ-2206 벽 부수고 이동하기 Swift  (0) 2023.06.30
BOJ-16435 스네이크버드 Swift  (0) 2023.06.29

문제

명우는 홍준이와 함께 팰린드롬 놀이를 해보려고 한다.

먼저, 홍준이는 자연수 N개를 칠판에 적는다. 그 다음, 명우에게 질문을 총 M번 한다.

각 질문은 두 정수 S와 E(1 ≤ S ≤ E ≤ N)로 나타낼 수 있으며, S번째 수부터 E번째 까지 수가 팰린드롬을 이루는지를 물어보며, 명우는 각 질문에 대해 팰린드롬이다 또는 아니다를 말해야 한다.

예를 들어, 홍준이가 칠판에 적은 수가 1, 2, 1, 3, 1, 2, 1라고 하자.

  • S = 1, E = 3인 경우 1, 2, 1은 팰린드롬이다.
  • S = 2, E = 5인 경우 2, 1, 3, 1은 팰린드롬이 아니다.
  • S = 3, E = 3인 경우 1은 팰린드롬이다.
  • S = 5, E = 7인 경우 1, 2, 1은 팰린드롬이다.

자연수 N개와 질문 M개가 모두 주어졌을 때, 명우의 대답을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수열의 크기 N (1 ≤ N ≤ 2,000)이 주어진다.

둘째 줄에는 홍준이가 칠판에 적은 수 N개가 순서대로 주어진다. 칠판에 적은 수는 100,000보다 작거나 같은 자연수이다.

셋째 줄에는 홍준이가 한 질문의 개수 M (1 ≤ M ≤ 1,000,000)이 주어진다.

넷째 줄부터 M개의 줄에는 홍준이가 명우에게 한 질문 S와 E가 한 줄에 하나씩 주어진다.

출력

총 M개의 줄에 걸쳐 홍준이의 질문에 대한 명우의 답을 입력으로 주어진 순서에 따라서 출력한다. 팰린드롬인 경우에는 1, 아닌 경우에는 0을 출력한다.

내가 푼 풀이

- 처음에는 주어진 질문에대한 모든 경우의 수에서 팰린드롬인지 구하려고 했지만, 수열의 크기를 감안했을 때 시간초과가 날 거라 생각했다.

- dp를 이용하여 dp 배열에 저장하고, 질문들을 해당 배열에서 꺼내오려한다.

- dp에 저장하기 위해 팰린드롬의 성질을 좀 더 생각해봐야 했다.

- 여기서 이용했던 팰린드롬의 성질은 주어진 수열에서 s번째부터 e까지의 수열이 팰린드롬이라면, s+1번째부터 e-1까지의 수열도 역시 팰린드롬이 된다.

- 예로 위에 주어진 수열 1, 2, 1, 3, 1, 2, 1에서 0번째부터 6번째까지의 수열이 1, 2, 1, 3, 1, 2, 1이고, 해당 수열은 팰린드롬이다.

- 0번째부터 6번째까지의 수열이 팰린드롬이라면, 1번째부터 5번째까지의 수열도 역시 팰린드롬이다. ( 2, 1, 3, 1, 2 )

- 위의 성질을 이용하기 위해선 주어진 수열의 길이가 최소 3이어야 한다.

- 수열의 길이가 1이라면 원소 자기 자신하나로 팰린드롬이 된다.

- 수열의 길이가 2라면 원소 하나와 그다음 원소가 같다면, 팰린드롬이 된다.

- 수열의 길이가 3 미만인 경우의 수는 위와 같이 구하고, 3 이상인 경우는 아래와 같이 구한다.

- dp [i][j] = i번째부터 j번째까지의 수열이 팰린드롬인가? ( 팰린드롬이라면 1을 저장, 아니라면 0을 저장)

- 위 성질을 이용하여 수열의 길이가 3이상이라면, 두가지 경우의 수를 판단하면된다.

1. 수열의 양 끝 원소가 같은지?

2. 주어진 수열의 s+1번째부터 e-1까지의 수열이 팰린드룸인지?

 

해당 문제는 많은 입력과 출력을 요구하므로, readLine을 이용한 입력및 print 출력을 남용하면 시간초과가 뜬다.

더 빠른 FileIO를 이용하여 입력 및 한 문자열에 저장하여 한번에 출력하는 방식을 이용한다.

 

코드로 구현해보자.

import Foundation

// Swift 입출력
final class FileIO {
    private var buffer:[UInt8]
    private var index: Int
    
    init(fileHandle: FileHandle = FileHandle.standardInput) {
        buffer = Array(fileHandle.readDataToEndOfFile())+[UInt8(0)]
        index = 0
    }
    
    @inline(__always) private func read() -> UInt8 {
        defer { index += 1 }
        
        return buffer.withUnsafeBufferPointer { $0[index] }
    }
    
    @inline(__always) func readInt() -> Int {
        var sum = 0
        var now = read()
        var isPositive = true
        
        while now == 10
                || now == 32 { now = read() }
        if now == 45{ isPositive.toggle(); now = read() }
        while now >= 48, now <= 57 {
            sum = sum * 10 + Int(now-48)
            now = read()
        }
        
        return sum * (isPositive ? 1:-1)
    }
    
    @inline(__always) func readString() -> String {
        var str = ""
        var now = read()
        
        while now == 10
                || now == 32 { now = read() }
        
        while now != 10
                && now != 32 && now != 0 {
            str += String(bytes: [now], encoding: .ascii)!
            now = read()
        }
        
        return str
    }
}

// 입력
let fileIO = FileIO()
let N = fileIO.readInt()
var arr = [Int]()
for i in 0..<N {
    arr.append(fileIO.readInt())
}
let M = fileIO.readInt()
var dp = Array(repeating: Array(repeating: 0, count: N), count: N)

// 수열의 길이가 1일때
for i in 0..<N {
    dp[i][i] = 1
}

// 수열의 길이가 2일때
for i in 0..<N-1 {
    if arr[i] == arr[i+1] {
        dp[i][i+1] = 1
    }
}

// 수열의 길이가 3이상일때
for i in (0..<N-2).reversed() {
    for j in (i+2..<N).reversed() {
        let idx = j
        if arr[i] == arr[idx] && dp[i+1][idx-1] == 1 {
            dp[i][idx] = 1
        }
    }
}
var answer = ""
for i in 0..<M {
    let s1 = fileIO.readInt()
    let s2 = fileIO.readInt()
    answer += "\(dp[s1-1][s2-1])\n"
}

print(answer)

문제

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다.

만약에 이동하는 도중에 한 개의 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 한 개 까지 부수고 이동하여도 된다.

한 칸에서 이동할 수 있는 칸은 상하좌우로 인접한 칸이다.

맵이 주어졌을 때, 최단 경로를 구해 내는 프로그램을 작성하시오.

입력

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

출력

첫째 줄에 최단 거리를 출력한다. 불가능할 때는 -1을 출력한다.

내가 푼 풀이

- 첫 시도로 백트래킹을 이용해 0,0 지점에서 N, M 지점까지 가는 경우의 수를 조사했지만, 시간초과가 떴다.

- 이전에 지나갔던 지점을 1로 변경하며 세 보았는데 이론적으로 틀린것 같다.

- 벽을 단 한번 부술 수 있지만, 벽을 아예 부수지 않아도 최단경로가 나올 수 있다.

- 이를 두가지 경우의 수로 최적의 경로를 탐색보다는 기록하는 방향으로 정했다.

- m 과 n은 최대 1000이므로 BFS로 딱 한번 탐색해내야 한다.

- 3차원 배열을 지정해 벽을 부순경우와 부수지 않은 경우 모두 기록하여 M, N 지점에 도달했을 때, 최단경로를 출력한다.

- M N 지점까지 이동하지 못한경우 -1 출력

- visited[z][x][y] : z 가 0인경우, 벽을 아직 부수지 않았다. , z가 1인경우 벽을 이미 한번 부쉈다.

 

 

import Foundation

// 입력
let input = readLine()!.split(separator: " ").map{ Int($0)! }
var arr = [[Int]]()
for i in 0..<input[0] {
    let a = Array(readLine()!).map{ Int(String($0))! }
    arr.append(a)
}

// 최단경로를 기록할 visited 배열과 BFS를 이용할 needVistedQueue 배열
var visited = Array(repeating: Array(repeating: Array(repeating: 0, count: input[1]), count: input[0]), count: 2)
var needVisitQueue = [(x: Int, y: Int, z: Int)]()

// 상하좌우 방향
let dx = [0,1,0,-1]
let dy = [1,0,-1,0]

// 결과 변수
var result = Int.max

// 출발지점 설정과 출발지점도 최단경로에 세므로 1로 초기화
needVisitQueue.append((x: 0, y: 0, z: 0))
visited[0][0][0] = 1


// BFS
var idx = 0
while idx < needVisitQueue.count {
    var loc = needVisitQueue[idx]
    idx += 1
    
    // 목표지점에 도착한 경우 최단경로 갱신
    if loc.x == input[0] - 1 && loc.y == input[1] - 1 {
        if result > visited[loc.z][loc.x][loc.y] && visited[loc.z][loc.x][loc.y] != 0 {
            result = visited[loc.z][loc.x][loc.y]
        }
        continue
    }
    for i in 0..<4 {
        let mx = dx[i] + loc.x
        let my = dy[i] + loc.y
        let mz = loc.z

        if mx >= 0 && mx < input[0] && my >= 0 && my < input[1] {
            // 다음 위치로 이동 할 수 있고, 아직 방문하지않은곳이라면
            if arr[mx][my] == 0 && visited[mz][mx][my] == 0 {
                visited[mz][mx][my] = visited[loc.z][loc.x][loc.y] + 1
                needVisitQueue.append((x: mx, y: my, z: mz))
            }
            // 다음 위치가 벽이고 아직 부수지 않았다면
            if arr[mx][my] == 1 && mz == 0 {
                visited[mz+1][mx][my] = visited[loc.z][loc.x][loc.y] + 1
                needVisitQueue.append((x: mx, y: my, z: mz + 1))
            }
        }
    }
}

if result == Int.max {
    print(-1)
} else {
    print(result)
}

문제

스네이크버드는 뱀과 새의 모습을 닮은 귀여운 생물체입니다. 

스네이크버드의 주요 먹이는 과일이며 과일 하나를 먹으면 길이가 1만큼 늘어납니다.

과일들은 지상으로부터 일정 높이를 두고 떨어져 있으며 i (1 ≤ i  N) 번째 과일의 높이는 hi입니다. 

스네이크버드는 자신의 길이보다 작거나 같은 높이에 있는 과일들을 먹을 수 있습니다.

스네이크버드의 처음 길이가 L일때 과일들을 먹어 늘릴 수 있는 최대 길이를 구하세요.

입력

첫 번째 줄에 과일의 개수 N (1 ≤ N ≤ 1,000) 과 스네이크버드의 초기 길이 정수 L (1 ≤ L ≤ 10,000) 이 주어집니다.

두 번째 줄에는 정수 h1, h2, ..., hN (1 ≤ hi ≤ 10,000) 이 주어집니다.

출력

첫 번째 줄에 스네이크버드의 최대 길이를 출력합니다.

내가 푼 풀이

- 스네이크버드는 자신의 길이보다 작거나 같은 높이의 과일을 먹을 수 있으므로 높이가 가장 낮은 과일부터 먹는다.

- 높이가 가장 낮은곳에 있는 과일부터 먹으며 과일을 못먹는경우 늘어난 길이 출력 , 다먹어도 출력

 

import Foundation

// 입력
let input = readLine()!.split(separator: " ").map{ Int($0)! }
var fruits = readLine()!.split(separator: " ").map{ Int($0)! }
var len = input[1]

// 과일의 높이가 담긴 배열 내림차순 정렬
fruits.sort{ $0 > $1 }

// 과일먹기
// 해당높이가 스네이크버드의 길이보다 작거나 같으면 먹고 길이가 자란다.
while !fruits.isEmpty {
    let food = fruits.removeLast()
    if len >= food {
        len += 1
    } else {
        break
    }
}
print(len)

문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50}인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

둘째 줄에는 가장 긴 증가하는 부분 수열을 출력한다. 그러한 수열이 여러가지인 경우 아무거나 출력한다.

내가 푼 풀이

- 이중 반복문으로 현재원소가 이전원소보다 크다면, dp에 저장된 배열 + 현재원소를 저장하여 가장 긴 증가하는 부분수열을 최신화한다.

- dp는 2차원배열로 각 인덱스는 해당 위치에서 가장 긴 부분수열을 갖는다.

 

import Foundation

// 입력
let input = Int(readLine()!)!
var arr = readLine()!.split(separator: " ").map{ Int($0)! }

// r: 결과배열, dp: 가장 긴 부분수열을 저장할 배열
var r = [Int]()
var dp = Array(repeating: [Int](), count: input)

// 수열의 각 원소는 최소 자신만 갖는 부분수열로 길이가 1이다.
// 현재원소가 이전원소보다 크다면 이전원소의 dp에 저장된 배열 + 현재원소를 저장하여 최신화
for i in 0..<arr.count {
    dp[i] = [arr[i]]
    for j in 0..<i {
        if arr[i] > arr[j] {
            var a = dp[j]
            a.append(arr[i])
            if a.count > dp[i].count {
                dp[i] = a
            }
        }
    }
    // 가장 긴 부분수열 최신화
    if dp[i].count > r.count {
        r = dp[i]
    }
}

print(r.count)
print(r.map{String($0)}.joined(separator: " "))

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-2206 벽 부수고 이동하기 Swift  (0) 2023.06.30
BOJ-16435 스네이크버드 Swift  (0) 2023.06.29
BOJ-1987 알파벳 Swift  (0) 2023.06.14
BOJ-15904 UCPC는 무엇의 약자일까? Swift  (0) 2023.06.13
BOJ-1890 점프 Swift  (0) 2023.06.13

문제

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다.

말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.

좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.

입력

첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1 ≤ R,C ≤ 20) 둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.

출력

첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.

내가 푼 풀이

- 문제의 원리는 어렵지않았다.

- (0, 0)에서 시작하여 해당 지점 알파벳이 중복되지않게 최대로 가는 경우의 수를 구하는데 백트래킹이 생각났다.

- 한 쪽으로 알파벳이 중복되지 않을만큼 이동했다가, 중복이된다면 이전 기점으로 돌아와 재탐색한다.

- 처음에는 배열의크기가 최대 20 * 20 이라 단순히 DFS 백트래킹 방식으로 풀면 되겠다 했는데 시간초과가 떴다.

- 탐색하면서 넣는 배열을 확인하는 contains 함수의 시간복잡도가 O(N)이라 여기서 문제인듯 했다.

- Dictionary를 26크기만큼 선언해 알파벳을 만나면 값을 1로 변경하여 중복을 확인하는 방법을 2차로 사용했지만, 이것도 역시 시간초과가 떴다.

- 여기서 더이상 줄일 방법이 떠오르지 않아서 다른 분들이 푼 풀이를 참고했다.

- 백트래킹 DFS 로 푸는방법은 맞았지만, Swift는 시간제한이 빡빡해서 비트마스킹을 사용했다.

- A : 0, B: 1 ... Z: 25 로 지정하고, 알파벳을 만나면 쉬프트 연산자를 이용하여 비트에 넣어준다.

- 다음 알파벳을 비트에 넣은 후 AND 연산을 해서 0이되면, 중복되지 않은 알파벳이고, 0이 아니면 중복된 알파벳으로 판단한다.

- 배열과 딕셔너리를 이용하여 중복알파벳을 판단했는데, 정수 하나로 판단하니 시간이 확 줄어들었다.

- 비트마스킹 기억해두도록 하자.

 

import Foundation

let input = readLine()!.split(separator: " ").map{ Int($0)! }
let r = input[0]
let c = input[1]
var arr = [[Int]]()
var result = 0
let dx = [0,1,0,-1]
let dy = [1,0,-1,0]

// 알파벳 비트마스킹
for i in 0..<r {
    arr.append(readLine()!.map{ Int($0.asciiValue!) - 65 })
}

// DFS 백트래킹
func dfs(x: Int, y: Int, count: Int, alphabet: Int) {
    result = max(result, count)

    for i in 0..<4 {
        let mx = dx[i] + x
        let my = dy[i] + y

        if (mx >= 0 && mx < r) && (my >= 0 && my < c) && (alphabet & 1 << arr[mx][my] == 0) {
            dfs(x: mx, y: my, count: count+1, alphabet: alphabet | 1 << arr[mx][my])
            
        }
    }

}

dfs(x: 0, y: 0, count: 1, alphabet: 1 << arr[0][0])
print(result)

 

문제

UCPC는 '전국 대학생 프로그래밍 대회 동아리 연합 여름 대회'의 줄임말로 알려져있다. 하지만 이 줄임말이 정확히 어떻게 구성되었는지는 아무도 모른다. UCPC 2018을 준비하던 ntopia는 여러 사람들에게 UCPC가 정확히 무엇의 줄임말인지 물어보았지만, 아무도 정확한 답을 제시해주지 못했다. ntopia가 들은 몇 가지 답을 아래에 적어보았다.

  • Union of Computer Programming Contest club contest
  • Union of Computer Programming contest Club contest
  • Union of Computer Programming contest club Contest
  • Union of Collegiate Programming Contest club contest
  • Union of Collegiate Programming contest Club contest
  • Union of Collegiate Programming contest club Contest
  • University Computer Programming Contest
  • University Computer Programming Club contest
  • University Computer Programming club Contest
  • University Collegiate Programming Contest
  • University CPC
  • ...

ntopia는 이렇게 다양한 답을 듣고는 UCPC가 무엇의 약자인지는 아무도 모른다고 결론내렸다. 적당히 슥삭해서 UCPC를 남길 수 있으면 모두 UCPC의 약자인 것이다!

문자열이 주어지면 이 문자열을 적절히 축약해서 "UCPC"로 만들 수 있는지 확인하는 프로그램을 만들어보자.

축약이라는 것은 문자열에서 임의의 문자들을 제거하는 행동을 뜻한다. 예를 들면, "apple"에서 a와 e를 지워 "ppl"로 만들 수 있고, "University Computer Programming Contest"에서 공백과 소문자를 모두 지워 "UCPC"로 만들 수 있다.

문자열을 비교할 때는 대소문자를 구분해 정확히 비교한다. 예를 들어 "UCPC"와 "UCpC"는 다른 문자열이다. 따라서 "University Computer programming Contest"를 "UCPC"로 축약할 수 있는 방법은 없다.

그나저나 UCPC는 정말 무엇의 약자였을까? 정확히 아시는 분은 제보 부탁드립니다.

입력

첫 번째 줄에 알파벳 대소문자, 공백으로 구성된 문자열이 주어진다. 문자열의 길이는 최대 1,000자이다. 문자열의 맨 앞과 맨 끝에 공백이 있는 경우는 없고, 공백이 연속해서 2번 이상 주어지는 경우도 없다.

출력

첫 번째 줄에 입력으로 주어진 문자열을 적절히 축약해 "UCPC"로 만들 수 있으면 "I love UCPC"를 출력하고, 만들 수 없으면 "I hate UCPC"를 출력한다.

내가 푼 풀이

- 주어진 문자열에서 U C P C 차례로 존재하면 I love UCPC 출력, 존재하지 않다면 I hate UCPC 출력한다.

- 이중반복문으로 탐색한다.

 

import Foundation

var str = ["U", "C", "P", "C"]
var arr = readLine()!.split(separator: " ").map{ String($0) }
var idx = 0

for i in arr {
    for j in i {
        let s = String(j)
        if idx < str.count && s == str[idx] {
            idx += 1
        }
    }
}

if idx == 4 {
    print("I love UCPC")
} else {
    print("I hate UCPC")
}

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-14002 가장 긴 증가하는 부분 수열 4 Swift  (0) 2023.06.29
BOJ-1987 알파벳 Swift  (0) 2023.06.14
BOJ-1890 점프 Swift  (0) 2023.06.13
BOJ-7562 나이트의 이동 Swift  (1) 2023.06.12
BOJ-1041 주사위 Swift  (0) 2023.06.12

+ Recent posts