백준 등 알고리즘

[C#] 프로그래머스 LV 2 주차 요금 계산

박도치 2024. 12. 24. 15:44

https://school.programmers.co.kr/learn/courses/30/lessons/92341

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

 

설명이 엄청 길지만 주어진 기본요금, 추가요금, 기본시간을 계산해서 차량이 들어오고 나갈때 의 시간을 계산해주면 된다.

 

그렇다면 차량이 들어왔을 때 주차장 일지에 등록하듯이 dictionary를 통해 차를 넣어주고, 나갈때 최초의 등록이라면 그냥 추가만하고 이전에 등록한 적이 있었다면 더해주면 된다.

 

그리고 23:59 까지 출차하지 않았다면 그 계산도 따로 더해주면 된다.

 

전체 코드는 아래로 내리면 있기 때문에 참고하면 된다.

 

 1. 요금 계산 및 split으로 파트 나누기

public int[] solution(int[] fees, string[] records)
{

    int baseTime = fees[0];   // 기본 시간 (분)
    int baseFee = fees[1];    // 기본 요금 (원)
    int unitTime = fees[2];   // 단위 시간 (분)
    int unitFee = fees[3];    // 단위 요금 (원)

    foreach (var record in records)
    {
        string[] parts = record.Split(' ');
        string time = parts[0];
        string carNumber = parts[1];
        string status = parts[2];
    }

private int CalculateFee(int totalTime, int baseTime, int baseFee, int unitTime, int unitFee)
    {
        if (totalTime <= baseTime)
            return baseFee;

        double extraTime = totalTime - baseTime;
        int extraUnits = (int)Math.Ceiling(extraTime / unitTime);

        return baseFee + extraUnits * unitFee;
    }
}

 

먼저 fee(요금)은 배열로 다 나눠져 있기 때문에, 배열 순서대로 int로 옮겨주면 된다.

 

그리고 기록들은 예를들면 "05: 34 5961 IN" 이런식으로 되어있기 때문에 띄어쓰기 부분을 Split으로 나눠서 앞부분은 시간, 두번째는 차 번호 마지막은 In 혹은 Out의 여부를 담아주도록 한다.   

 

totalTime 은 추후에 나오겠지만 입차하고 출차한 기록을 쭉 계산한 모든 시간이며 나머지는 주어진 값을 매개변수로 전달해주도록 한다.

 

기본적으로 totaltime보다 기본 시간이 더 크면 즉, 기본 시간보다 주차를 덜 했다면 기본 요금만 내게끔 한다는 것이 문제 조건이었기 때문에 return해주도록 한다.

 

그게 아니라면 전체시간을 기본시간에서 뺀 후, 올림 계산으로 단위 시간을 나눠주도록 한다.

 

여기서 double로 한 이유는 Math.ceiling이 double을 매개변수로 취하기 때문에 double로 extratime을 먼저 계산해주고, 후에 parsing해준다.

 

계산식은 문제에 다 주어지는 방식이기 때문에 차근차근 따라하면 크게 어렵지 않다.

 

2. 시간 계산

시간을 편하게 계산하기 위해서는 분으로 만든 후, 이를 뺄셈하여 계산해준다. 예를 들어 5:00 이라면 시간에 * 60을 하여 300 으로 분으로 만들어서 이후에 시간의 차 계산과 요금 계산에 편하게끔 바꿔주도록 한다.

 

    private int TimeToMinutes(string time)
    {
        string[] parts = time.Split(':');
        int hours = int.Parse(parts[0]);
        int minutes = int.Parse(parts[1]);
        return hours * 60 + minutes;
    }

 

 

3. 입차와 출차 기록

 

두 개의 Dictionary로 기록한다. 입차 했을 때 입차 시각을 넣어두고, 출차할 때 얼마나 있었는지 계산하여 넣어둔다.

 

그리고 위에 말했듯 23:59분 이전에 출차기록이 없다면 해당 시간에 출차했다고 간주하여 계산해준다.

 

status로 IN과 OUT을 구분해뒀는데, 조건을 통해 IN이면 carnumber를 키값으로 입차시간을 기록해 둔다.

 

만약 IN이 아니면 나갔기 때문에 이전에 들어온 시간대가 있을것이다. 그러면 지금 시간에서 이전에 dictionary에 등록된 시간을 빼준것이 주차된 시간이다.

 

만약 기록이 있다면 즉 Dictionary.containsKey에 key값이 있다면 더해주고, 아니면 최초의 등록이기 때문에 시간만 기록한다.

 

Dictionary<string, int> parkingTime = new Dictionary<string, int>(); // 누적 주차 시간
        Dictionary<string, int> inTime = new Dictionary<string, int>();      // 입차 시각

        foreach (var record in records)
        {
            string[] parts = record.Split(' ');
            string time = parts[0];
            string carNumber = parts[1];
            string status = parts[2];

            int minutes = TimeToMinutes(time);

            if (status == "IN")
            {
                inTime[carNumber] = minutes;
            }
            else // OUT
            {
                int duration = minutes - inTime[carNumber];
                inTime.Remove(carNumber);

                if (parkingTime.ContainsKey(carNumber))
                {
                    parkingTime[carNumber] += duration;
                }
                else
                {
                    parkingTime[carNumber] = duration;
                }
            }
        }

        int closingTime = TimeToMinutes("23:59");
        foreach (var carNumber in inTime.Keys)
        {
            int duration = closingTime - inTime[carNumber];
            if (parkingTime.ContainsKey(carNumber))
            {
                parkingTime[carNumber] += duration;
            }
            else
            {
                parkingTime[carNumber] = duration;
            }
        }

 

 

전체 코드

 

using System;
using System.Collections.Generic;

public class Solution
{
    public int[] solution(int[] fees, string[] records)
    {
        int baseTime = fees[0];   // 기본 시간 (분)
        int baseFee = fees[1];    // 기본 요금 (원)
        int unitTime = fees[2];   // 단위 시간 (분)
        int unitFee = fees[3];    // 단위 요금 (원)

        Dictionary<string, int> parkingTime = new Dictionary<string, int>(); // 누적 주차 시간
        Dictionary<string, int> inTime = new Dictionary<string, int>();      // 입차 시각

        foreach (var record in records)
        {
            string[] parts = record.Split(' ');
            string time = parts[0];
            string carNumber = parts[1];
            string status = parts[2];

            int minutes = TimeToMinutes(time);

            if (status == "IN")
            {
                inTime[carNumber] = minutes;
            }
            else // OUT
            {
                int duration = minutes - inTime[carNumber];
                inTime.Remove(carNumber);

                if (parkingTime.ContainsKey(carNumber))
                {
                    parkingTime[carNumber] += duration;
                }
                else
                {
                    parkingTime[carNumber] = duration;
                }
            }
        }

        int closingTime = TimeToMinutes("23:59");
        foreach (var carNumber in inTime.Keys)
        {
            int duration = closingTime - inTime[carNumber];
            if (parkingTime.ContainsKey(carNumber))
            {
                parkingTime[carNumber] += duration;
            }
            else
            {
                parkingTime[carNumber] = duration;
            }
        }

        // 차량 번호 오름차순 정렬 및 요금 계산
        List<string> carNumbers = new List<string>(parkingTime.Keys);
        carNumbers.Sort(); // 차량 번호 오름차순 정렬

        List<int> result = new List<int>();

        foreach (string carNumber in carNumbers)
        {
            int totalTime = parkingTime[carNumber];
            int fee = CalculateFee(totalTime, baseTime, baseFee, unitTime, unitFee);
            result.Add(fee);
        }

        // 결과 배열로 변환
        int[] finalResult = result.ToArray();

        return finalResult;
    }

    private int CalculateFee(int totalTime, int baseTime, int baseFee, int unitTime, int unitFee)
    {
        if (totalTime <= baseTime)
            return baseFee;

        double extraTime = totalTime - baseTime;
        int extraUnits = (int)Math.Ceiling(extraTime / unitTime);

        return baseFee + extraUnits * unitFee;
    }

    private int TimeToMinutes(string time)
    {
        string[] parts = time.Split(':');
        int hours = int.Parse(parts[0]);
        int minutes = int.Parse(parts[1]);
        return hours * 60 + minutes;
    }

}