Machineboy空

Excercism - BookStore 조합 본문

Computer/Coding Test

Excercism - BookStore 조합

안녕도라 2025. 2. 14. 16:48

문제요약

주어진 책 가운데, 가장 높은 할인을 적용할 수 있는 조합을 찾아 총액을 도출하라.

 

https://exercism.org/tracks/csharp/exercises/book-store

 

Book Store in C# on Exercism

Can you solve Book Store in C#? Improve your C# skills with support from our world-class team of mentors.

exercism.org


난이도

Medium


풀이 포인트

  • 아이디어


REVIEW

 

우선 5개 그룹과 3개 그룹으로 나누어졌을 때보다, 4개와 4개 그룹으로 나누어졌을 때 금액이 더 싸다는 사실을 간과했다.

그래서 모든 조합을 다 고려해야 하나.. 머리가 아파져서 모범 풀이를 봤더니

5개와 3개가 함께 있을 경우에만 4개와 4개로 쪼개어주는 처리를 해주면 되더라.

 

하지만 모범 풀이에는 Linq가 사용되어 있어 좀 이해가 어려웠다.

foreach (var set in sets){
	if (set.Count == 5 && sets.FirstOrDefault(s => s.Count == 3) is { } setOfThree)

5개 짜리 set 이 있다면 3개 짜리 set이 있는지 찾아, setOfThree라는 이름을 붙여 어떤 처리를 해주는 것.

 for (int i = 0; i < sets.Count; i++)
{
    if (sets[i].Count == 5)
    {
        for (int j = 0; j < sets.Count; j++)
        {
            if (sets[j].Count == 3)
            { 
            	// 처리 후 break;

for문으로 이해할 수 있게 고치면 이렇게..

 

여튼 중복되지 않도록 그룹을 나눠준 후에

5개와 3개가 함께 있을 경우에만 4개와 4개로 쪼개어주는 처리를 놓치지 않고 하면 되었던 문제..

오늘 푼 두 문제가 꽤 난이도가 있어 어떻게 푸는지 조차 그려지지 않자 좀 낙담했다..

근데 이 문제는 풀이를 보고 나니 그리 어렵진 않은 문제였군!

 


CODE

using System;
using System.Collections.Generic;
using System.Linq;

public static class BookStore
{
    public static decimal Total(IEnumerable<int> books)
    {
        List<List<int>> sets = new();
        foreach (var book in books)
        {
            bool added = false;
            foreach (var set in sets)
            {
                if (!set.Contains(book))
                {
                    set.Add(book);
                    added = true;
                    break;
                }
            }
            if (!added) sets.Add(new List<int> { book });
        }
        foreach (var set in sets)
        {
            if (set.Count == 5 && sets.FirstOrDefault(s => s.Count == 3) is { } setOfThree)
            {
                set.RemoveAt(0);
                setOfThree.Add(9);
            }
        }
        decimal total = 0;
        foreach (var set in sets)
        {
            var discount = set.Count switch
            {
                5 => 0.25m,
                4 => 0.2m,
                3 => 0.1m,
                2 => 0.05m,
                1 => 0,
                _ => throw new ArgumentException("whatever I wrote last time.")
            };
            total += 8 * set.Count * (1 - discount);
        }
        return total;
    }
}
using System;
using System.Collections.Generic;

public static class BookStore
{
    public static decimal Total(IEnumerable<int> books)
    {
        List<List<int>> sets = new();
        
        // 책 그룹 분배
        foreach (var book in books)
        {
            bool added = false;
            foreach (var set in sets)
            {
                if (!set.Contains(book))
                {
                    set.Add(book);
                    added = true;
                    break;
                }
            }
            if (!added) sets.Add(new List<int> { book });
        }
        // 결과: {1,2,3,4,5} {1,2,3}

        // 5,3 조합이면 떨어뜨리는 로직
        for (int i = 0; i < sets.Count; i++)
{
    if (sets[i].Count == 5)
    {
        for (int j = 0; j < sets.Count; j++)
        {
            if (sets[j].Count == 3)
            {
                sets[i].RemoveAt(0);    // 5권 세트에서 1권 제거
                sets[j].Add(9); // 3권 세트에 추가
                break;                   // 교환 후 반복문 종료
            }
        }
    }
}


        // 결과 {2,3,4,5} {1,2,3,9}

        // 전체 책 그룹에 돈 계산
        decimal total = 0;
        foreach (var set in sets)
        {
            switch(set.Count)
            {
                case 5: 
                    total += 8 * 5 * 0.75m;
                    break;
                case 4:
                    total += 8 * 4 * 0.8m;
                    break;
                case 3:
                    total += 8 * 3 * 0.9m;
                    break;
                case 2:
                    total += 8 * 2 * 0.95m;
                    break;
                case 1:
                    total += 8;
                    break;
                default:
                    break;
            }
        }
               return total;
    }
}