본문 바로가기
♞ | 공부일지

[Android, 내일배움캠프] 공부일지(2024-06-14)

by immgga 2024. 6. 14.
오늘 공부한 내용 정리(2024년 6월 14일)

 

 

1. 코드카타 문제풀이

A. 하키(백준, S4, 1358번)

문제 내용

 

문제 풀이 방법

  • 그림과 같은 하키장이 있을 때, 하키장 안에 있는 선수는 총 몇 명인지 출력.
  • 하키장에 선수가 있는 조건으로는
    x, y부터 x+w, y+h까지의 좌표 안의 직사각형 영역에 있는 경우,
    x좌표를 벗어나고, y좌표는 y부터 y+h 사이에 있는 경우, 왼쪽과 오른쪽 원의 중심과 해당 좌표와의 거리를 구해 그 거리가 원의 반지름보다 작거나 같은 경우.

 

해결 코드(스포 주의)

더보기
import java.util.Scanner
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.sqrt

fun main() = with(Scanner(System.`in`)) {
    val w = nextInt()
    val h = nextInt()
    val x = nextInt()
    val y = nextInt()
    val players = nextInt()

    // 하키장에 선수가 있는 조건.
    // 직사각형과 반원 2개로 구성되어 있을 때,
    // 직사각형 안에 선수가 있거나,
    // 원의 중심과 선수 간의 거리가 h/2(반지름)보다 작아야 함.

    // 직사각형의 좌표
    val startCoordinate = listOf(x, y)
    val squareMaxCoordinate = listOf(x+w, y+h)

    // 원의 중심 좌표
    val circleCenterCoordinate1 = listOf(x, y+(h/2))        // 왼쪽 원의 중심
    val circleCenterCoordinate2 = listOf(x+w, y+(h/2))      // 오른쪽 원의 중심

    var inHockeyStadium = 0     // 경기장 안에 있는 선수의 수.
    for (i in 0 until players) {
        val playerX = nextInt()
        val playerY = nextInt()

        // 선수가 직사각형의 좌표 안에 있음.
        if (playerX in startCoordinate[0] .. squareMaxCoordinate[0] && playerY in startCoordinate[1] .. squareMaxCoordinate[1]) {
            inHockeyStadium++
            continue
        }
        // 선수가 직사각형의 x좌표픞 왼쪽으로 벗어남(y는 사이에 있음).
        else if (playerX < x && playerY in startCoordinate[1] .. squareMaxCoordinate[1]) {
            val distance = getDistanceBetweenPoints(playerX, playerY, circleCenterCoordinate1[0], circleCenterCoordinate1[1])
            if (distance <= h/2) {
                inHockeyStadium++
            }
            continue
        }
        // 선수가 직사각형의 x좌표를 오른쪽으로 벗어남(y는 사이에 있음).
        else if (playerX > x && playerY in startCoordinate[1] .. squareMaxCoordinate[1]) {
            val distance = getDistanceBetweenPoints(playerX, playerY, circleCenterCoordinate2[0], circleCenterCoordinate2[1])
            if (distance <= h/2) {
                inHockeyStadium++
            }
            continue
        }
    }

    println(inHockeyStadium)
}

// 두 점 사이의 거리를 구한다.
private fun getDistanceBetweenPoints(x1: Int, y1: Int, x2: Int, y2: Int): Double {
    val distanceX = abs(x1 - x2).toDouble()
    val distanceY = abs(y1 - y2).toDouble()

    return sqrt(distanceX.pow(2) + distanceY.pow(2))
}

 

풀이 과정

  • 입력받은 x, y를 startCoordinate로 만들어 주고, w, h도 입력받아 직사각형의 끝 좌표를 구해 준다(squareMaxCoordinate).
  • x, y+(h/2)와 x+w, y+(h/2)는 원의 중심의 좌표이므로 이 데이터도 변수로 저장한다(circleCenterCoordinate)
  • players만큼 반복한다.
    player의 x와 y를 입력받고
    선수의 좌표가 직사각형 좌표 내부에 있는 경우에 경기장에 있는 선수의 수(inHockeyStadium)를 1씩 늘린다.
    직사각형의 x범위는 벗어났지만 y 범위에는 있는 경우, x가 왼쪽으로 벗어난 경우 왼쪽의 원의 중심 좌표와 벗어난 선수의 좌표 간의 거리를 구한다(getDistanceBetweenPoints()). 구한 좌표가 원의 반지름(h/2) 보다 작거나 같아야 한다. 오른쪽의 경우도 동일하게 처리한다(왼쪽은 circleCenterCoordinate1로, 오른쪽은 circleCenterCoordinate2로 처리).
  • 구해진 선수의 count를 출력한다.

 

문제 해결 과정

  • 두 점 사이의 거리 공식을 알고 있으면 쉽게 해결할 수 있는 문제이다.
  • 위 공식을 쓰지 못하면 풀기 매우 힘들 것 같다.
  • 문제를 어떻게 풀어야 할지 감이 안 잡혀서 검색해서 문제 접근법을 봐보니 바로 감이 잡혀서 15분 만에 해결했다.

 

B. 동전 0(백준, S4, 11047번)

문제 내용

 

문제 풀이 방법

  • 동전의 종류 n과 k가 주어지고 동전의 가치 a가 n번 주어질 때, a를 최소로 써서 k를 만드는 경우의 a의 사용 횟수를 출력.

 

해결 코드(스포 주의)

더보기
import java.io.BufferedReader
import java.io.InputStreamReader

fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
    var (kindCoins, money) = readLine().split(" ").map { it.toInt() }
    var coinCnt = 0

    val coinArray = Array(kindCoins) { 0 }
    for (i in kindCoins-1 downTo  0) {
        val coin = readLine().toInt()
        coinArray[i] = coin
    }

    for (i in coinArray.indices) {
        if (money == 0) break

        val coin = coinArray[i]
        if (coin <= money) {
            val divValue = money / coin
            money %= coin
            coinCnt += divValue
        }
    }

    println(coinCnt)
}

 

풀이 과정

  • kindCoins, money를 입력받아 kindCoins -1부터 0까지 반복해 동전의 가치(coin)를 입력받아 coinArray에 저장한다.
    역순으로 저장한 것은 이따가 동전을 사용할 때, 고가치의 동전을 우선적으로 사용하기 위함이다.
  • coinArray의 크기만큼 반복을 다시 돌려서 coin(coinArray[i])가 현재 money보다 크면 동전을 사용할 수 있으므로 money / coin을 divValue로 저장하고, money를 money % coin으로 변경한다. money에 coin을 나눈 나머지가 들어가야 하기 때문이다.
    coinCnt를 divValue만큼 증가시킨다.

 

문제 해결 과정

  • 그리디 알고리즘의 아주 기초적인 문제이다.
  • 그리디 알고리즘을 제대로 공부하지는 않았지만, 큰 수부터 탐색해 원하는 결과를 얻는 방식이라고 알고 있다.
    추후에 그리디 알고리즘을 공부해 볼까?

 

2. 코틀린 개념 복습

A. 상속

복습 내용 간단 정리

블로그 링크: https://rkdrkd-history.tistory.com/121

 

[Kotlin] 상속(Inheritance)

상속이란?부모의 자원을 자식이 물려받아 사용하는 것을 상속이라고 한다. 상속은 클래스 간의 관계를 정의하고 코드의 재사용성을 높이기 위해 사용된다. 상속을 통해 하나의 클래스가 다른

rkdrkd-history.tistory.com

 

 

3. 개인 공부

A. 개인 과제(Lv.3)

과제 내용 간단 정리

Lv.3에서 구현할 내용은 Lv.2의 메뉴 클래스들을 상속 관계로 만들어 중복 코드를 최대한 줄이는 것이다.

그리고 메뉴들을 arrayList로 관리하는 것이다.

 

우선 상속 관계부터 만들어주겠다.

햄버거, 음료, 서브 메뉴를 한 번에 관리할 Food 클래스를 생성한다. Food 클래스에는 햄버거, 음료, 서브 메뉴에 공통적으로 들어가는 displayInfo()를 만들어서 println()까지 구현한다.

import src.food.category.Category

open class Food(
    val foodNum: Int,
    val name: String,
    val price: Int,
    val description: String,
    val category: Category
) {
    fun displayInfo() {
        println("$foodNum. $name                  | W$price | $description")
    }
}

 

추후에 어떤 카테고리의 메뉴인지 arrayList에서 골라내야 하기 때문에 enum class를 만들어 준다.

enum class Category {
    HAMBURGER,
    DRINK,
    SUBMENU
}

 

 

Food 클래스를 상속받을 클래스를 다시 만들어주었다.

Food 클래스의 프로퍼티를 받아오기 위해 클래스 파라미터를 구성해주었다.category 파라미터는 클래스 이름이 Burger()인 이상 무조건 Category.HAMBURGER 고정이기 때문에 따로 생성해주지 않았다.

import src.food.Food
import src.food.category.Category

class Burger(
    foodNum: Int,
    name: String,
    price: Int,
    description: String
): Food(foodNum, name, price, description, Category.HAMBURGER) {
}

클래스 내부는 비어 있지만, Food의 displayInfo()는 그대로 사용할 수 있다.

Drink()와 SubMenu()도 위와 같은 방법으로 구현했다.

Lv.2 때 사용한 클래스들은 모두 삭제했다.

 

 

이제 데이터를 담을 클래스들을 만들었으니, arrayList를 만들 차례이다. arrayList는 한 번 만들면 웬만한 클래스에서 거의 다 쓰일 것 같아서 singleton 패턴을 공부해 한 번만 생성하고 다른 클래스에서 쓰기 편하도록 만들어 주었다. 소지금도 물건 구입할 때 자주 쓰일 듯해서 같이 singleton으로 빼주었다.

import src.food.Food

class FoodData {
    companion object {
        val foodList = arrayListOf<Food>()

        fun addFood(food: Food) {
            foodList.add(food)
        }
    }
}

class OwnMoney {
    companion object {
        var ownMoney = 0

        fun initMoney(money: Int) {
            ownMoney = money
        }

        fun minusMoney(pay: Int) {
            ownMoney -= pay
        }
    }
}

두 개의 데이터가 사용되는 용도가 달라서 클래스를 분리시켰다.

추후에 singleton을 자세히 공부해 블로그에 올려 보겠다.

 

 


 

오늘 공부 내용 정리 및 회고

  • 개인 과제는 주말을 통해 Lv.4까지 구현하고자 한다.
  • 과제 Lv.3을 구현하기 위해 상속을 다시 공부했다. 내 눈에는 아주 잘 짜인 코드 같아 보이지만, 튜터님들에게는 어떻게 보일지 모르겠다. 과제 제출을 하고 생각하자. 문제 사항이 있으면 고치면 되니까.
  • 알고리즘은 계속 DP 문제를 풀고 있다. 골드 DP 문제는 아직도 많이 어려웠다. 해설을 보고 풀어도 내가 나중에 이걸 완전히 이해해서 다른 문제에서 써먹을 수 있을지 걱정이 앞선다.
    하지만 어쩌겠는가? 계속해봐야지.
  • DP 문제를 풀다가 그리디 알고리즘 문제를 풀어봤는데 그리디 기초문제만 풀어서 그런가 매우 쉽게 풀었다.
    DP를 기본적으로 사용할 수 있을 경지까지 오르면 다음 알고리즘으로는 그리디 알고리즘을 공부해 볼까?
728x90

댓글