이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

Harry Potter

출처 : http://codingdojo.org/cgi-bin/index.pl?KataPotter

해리포터 시리즈가 시중에 1~5권 까지 나와 있다고 한다. (현재는 더 많은 시리즈가 있긴 하지만..)

책 한권의 가격은 8 EUR 이다.

하지만 다음과 같은 조건으로 책 값을 할인 받을 수 있다고 한다.

  • 서로 다른 두 권을 구입하면 5% 할인
  • 서로 다른 세 권을 구입하면 10% 할인
  • 서로 다른 네 권을 구입하면 20% 할인
  • 서로 다른 다섯 권(전부!)을 구입하면 25% 할인

여러분은 이제 저마다 쇼핑카트에 가득 해리포터 책들을 담고 있는 손님들을 위해 가장 적은 금액으로 책들을 구입할 수 있도록 도와주는 알고리즘을 작성해야 한다.

예를 들어 다음과 같이 책을 구입한다면

  • 2 copies of the first book
  • 2 copies of the second book
  • 2 copies of the third book
  • 1 copy of the fourth book
  • 1 copy of the fifth book

여러분이 작성한 알고리즘을 이용하면 51.20 EUR 이라는 최저가가 나와야 한다.


테스트 케이스

def test_basics
  assert_equal(0, price([]))
  assert_equal(8, price([0]))
  assert_equal(8, price([1]))
  assert_equal(8, price([2]))
  assert_equal(8, price([3]))
  assert_equal(8, price([4]))
  assert_equal(8 * 2, price([0, 0]))
  assert_equal(8 * 3, price([1, 1, 1]))
end

def test_simple_discounts
  assert_equal(8 * 2 * 0.95, price([0, 1]))
  assert_equal(8 * 3 * 0.9, price([0, 2, 4]))
  assert_equal(8 * 4 * 0.8, price([0, 1, 2, 4]))
  assert_equal(8 * 5 * 0.75, price([0, 1, 2, 3, 4]))
end

def test_several_discounts
  assert_equal(8 + (8 * 2 * 0.95), price([0, 0, 1]))
  assert_equal(2 * (8 * 2 * 0.95), price([0, 0, 1, 1]))
  assert_equal((8 * 4 * 0.8) + (8 * 2 * 0.95), price([0, 0, 1, 2, 2, 3]))
  assert_equal(8 + (8 * 5 * 0.75), price([0, 1, 1, 2, 3, 4]))
end

def test_edge_cases
  assert_equal(2 * (8 * 4 * 0.8), price([0, 0, 1, 1, 2, 2, 3, 4]))
  assert_equal(3 * (8 * 5 * 0.75) + 2 * (8 * 4 * 0.8), 
    price([0, 0, 0, 0, 0, 
           1, 1, 1, 1, 1, 
           2, 2, 2, 2, 
           3, 3, 3, 3, 3, 
           4, 4, 4, 4]))
end

2014/12/26 16:29

pahkey

51.20 이 아니라 51.60 아닌가요? 8*5*0.75 + 8*3*0.90 = 51.60 인데요..... - 취미로재미로, 2016/02/05 15:17
+1 1,2,3,4 1,2,3,5 이렇게 구매하면 51.2 - stardust, 2017/01/04 14:33

21개의 풀이가 있습니다.

한계비용을 최소화하는 바구니에 책을 넣는 방법으로 만들었습니다.

import copy
def price(books):
    baskets = []
    for book in books:
        marginalcost = []
        for basket in baskets:
            temp_basket = copy.deepcopy(basket)
            temp_basket.add(book)
            marginalcost.append(calc(temp_basket) - calc(basket))
        try:
            minvalue = min([x for x in marginalcost if x])
            baskets[marginalcost.index(minvalue)].add(book)
        except:
            baskets.append({book})
    return sum([calc(x) for x in baskets])


def calc(bookset):
    DISCOUNT_RATE = (1, 1, 0.95, 0.9, 0.8, 0.75)
    if not bookset:
        return 0
    else:
        return len(bookset) * 8 * DISCOUNT_RATE[len(bookset)]

2014/12/28 14:59

투플러스

굉장히 효율적인 알고리즘인거 같습니다. 좀 자세한 설명 부탁드려도 될까요? - pahkey, 2014/12/29 16:05
취미로 배우는 초보인데, 칭찬해주셔서 감사합니다. 1. 책 리스트를 받습니다.(books) 2. 최적의 경우를 계산할 수 있도록 바구니들의 리스트를 만듭니다.(baskets) 3. 책 리스트에서 책을 한권씩 꺼냅니다(book). 4. 이미 책 바구니가 있는 경우에는 책을 각 바구니에 시험삼아 넣어 보고, 각 바구니에 넣었을 때의 한계비용을 측정합니다. 각 바구니의 한계비용은 한계비용 리스트 내(marginalcost) 각각 저장합니다. 한계비용 = 한 권의 책을 추가로 넣었을 경우 늘어나는 비용 ex. {0, 1} 인 바구니에 2를 넣는 경우 한계비용은 8(책가격)*3(권수)*0.9(할인율) - 8*2*0.95(원래 바구니의 책값) 21.6-15.2 = 6.4 (바구니들은 set이기 때문에 바구니에 이미 있는 항목을 넣는 행동은 무효입니다. 따라서 marginalcost를 0으로 만듭니다.) 5. 0이 아닌 한계비용 중에서 최소값을 구합니다. 5.1. 한계비용이 가장 작은 바구니에 책을 넣습니다. 5.2. 각 바구니의 한계비용이 모두 0이거나 바구니가 한개도 없으면 바구니를 하나 만들고 그 안에 책을 넣습니다. 6. 각 책에 대해 3~5를 반복합니다. 7. 책을 바구니에 모두 잘 넣었으면 각 바구니의 책값을 모두 합산하여 가격을 알려줍니다. - 투플러스, 2014/12/30 18:44
설명 감사합니다. set 을 이용해서 중복일 경우 무효처리하는 부분이 흥미롭네요 ^^, 거의 최적의 알고리즘인 것 같은데 이런 생각을 하신게 대단한거 같네요.. 전 재귀로 풀어보다가 느린 속도에 멘붕하고 포기하고 있었거든요. - pahkey, 2014/12/30 23:01
알고리즘은 잘 설명해 주셨는데 제가 초보라.. 코드가 잘 읽어 지지가 않네요; 함수 콜 방법이 price([2,2,2,1,1]) 이렇게 하면 되는게 맞나요? 결과 값이 다르게 나와서요 - Starleaguer, 2015/03/22 13:23
price([2,2,2,1,1]) 하면 [{2}] [{2}, {2}] [{2}, {2}, {2}] [{1, 2}, {2}, {2}] [{1, 2}, {1, 2}, {2}] 요렇게 돼서 38.4가 나오네요 - 투플러스, 2015/03/26 21:37

python 3.4.1 에서 만들어본 코드입니다.
기본적으로는 인자로 들어오는 책 리스트에서 가장 긴 (서로 다른) 책 묶음을 가려내서 계산하고,
그 묶음을 뺀 나머지 책 리스트에서 가장 긴 책 묶음을 가려내서 또 계산하는 걸 반복합니다.
하지만 책 할인율이 2권 5%, 3권 10%, 4권 20%, 5권 25% 으로,
3권에서 4권으로 넘어갈 때 할인율이 5% 가 아닌 10% 가 증가하기 때문에,
5권, 3권 조합보다는 4권, 4권 조합이 전체 가격을 낮추게 됩니다. 이 외의 경우에는 모두 그냥 가장 긴 (서로 다른) 책 묶음을 가려내서 계산하면 됩니다.

BOOK_PRICE = {1: 8 * 1,
              2: 8 * 0.95,
              3: 8 * 0.9,
              4: 8 * 0.8,
              5: 8 * 0.75}

def subtract_list_set(olist, oset):
    subtracted_list = [item if item not in oset else oset.remove(item) for item in olist]
    return([item for item in subtracted_list if item is not None])

def price(input_list):
    output_list = []
    while len(input_list) != 0:
        largest_pairs = set(input_list)
        output_list.append(len(largest_pairs))
        input_list = subtract_list_set(input_list, largest_pairs)
    if 5 in output_list and 3 in output_list:
        output_list.remove(5)
        output_list.remove(3)
        output_list.extend([4, 4])
    result = [item * BOOK_PRICE[item] for item in output_list]
    return(sum(result))

2015/01/05 22:38

Tim

3권 5권일때보다 4권 4권일때가 더 싸고 나머지의 경우엔 쌓일수록 싸기 때문에 일단 5권 묶음이 최대한으로 나오도록 한 다음 3권 5권 묶음을 4권4권으로 바꾸었습니다.

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
    int books[5]={1,1,2,2,2};
    int basket[5]={0,},t=0;
    int books_price[5]={300,256,216,152,80};
    sort(books,books+5);
    for(int i=0;i<5;i++)
    {
        basket[i]=books[i]-t;
        t=books[i];
    }
    if(basket[0]>basket[2])
    {
        basket[0]-=basket[2];
        basket[1]+=(basket[2]*2);
        basket[2]=0;
    }
    else
    {
        basket[2]-=basket[0];
        basket[1]+=(basket[0]*2);
        basket[0]=0;
    }
    int sum=0;
    for(int i=0;i<5;i++)
        sum+=books_price[i]*basket[i];
    printf("%lf\n",sum/10.0);

    return 0;
}

다른분들 풀이를 보니 초보자는 웁니다 ㅠㅠ

2015/01/28 10:18

정기석

O(k)로 해결해서 잘풀었다고 생각하고 있었는데 ... 초보자는 울다니요ㅜ 낚였습니다...; 늦었지만 저도 같은 알고리즘을 생각해서 풀었네요~ - Starleaguer, 2015/03/23 01:56

일단 조건은 만족했는데 쪼개는 부분의 코드가 좀 지저분 하네요.

class Books < Array
  FULL_SET = [*0..4]
  def price
    if uniq?
      8 * size * (1.0 - discount_rate)
    else
      uniqs, others = split
      uniqs.price + others.price
    end
  end

  private
  def uniq?
    uniq.size == size
  end

  def split
    set_index = []
    uniqs = Books.new
    others = dup
    others.each_with_index do |book, index|
      if !uniqs.include?(book) && FULL_SET.include?(book)
        set_index.unshift index
        uniqs << book
      end
    end
    set_index.each { |i| others.delete_at(i) }
    if others.uniq.size == 3 && uniqs.size == 5
      i = (uniqs - others.uniq).first
      uniqs.delete i
      others << i
    end
    [uniqs, others]
  end

  def discount_rate
    case size
    when 2 then 0.05
    when 3 then 0.10
    when 4 then 0.20
    when 5 then 0.25
    else
      0
    end
  end
end

def price(books)
  Books.new(books).price
end

2014/12/28 10:15

Shim Won

# 주어진 문제에서 모든 가격 책정의 경우를 구하기 위해 분할을 이용하였습니다. 예를 들어, 예시에 나오는 8권은 5+3, 5+2+2, 4+4, 4+2+2, 등등등 많은 분할의 수를 가집니다. 이걸 다 구하고 더해서 가장 작은 값을 출력하였습니다. 이 코드에 좋은 점은 100권 0권 2권 17권 0권 이런 식의 다양한 경우에 대해서도 신뢰할 수 있는 값을 구할 수 있다는 것입니다.(왜냐면 무식하게 다 구한거니깐...)

def bookdiscount():

    print "Choose the Harry Potter Edition.(input NUNMER as integer)"

    a = []
    for i in range(5):
        a.append(int(raw_input("%s'th edition : " % (i+1))))

    book = 0
    kind = 0

    for i in a:
        book = book + i
        if i>0: kind = kind +1

    pp = []
    pt = []
    ct = []

    for i in range(kind):
        k = kind - i
        for b in range((book/k)):
            pt = f(book-b*k, k)
            pt.extend([k]*b)
            pt.sort()
            pp.append(pt)

    for i in range(len(pp)):
        for j in pp[i+1:]:
            if pp[i] == j:
                pp.remove(j)

    for l in pp:
        ct.append(cost(l))

    ct.sort()
    set(ct)

    print "Possible Cost : "+str(list(set(ct)))     
    print "Minimum Cost is %s EUR." % ct[0]



def f(b, k):
    p = []

    while b > k:
        p.append(k)
        b = b-k
    p.append(b)

    return p


def cost(l):

    cos = 0

    for i in l:
        if i==1: cos = cos + 8
        elif i==2: cos = cos + 8*i*0.95
        elif i==3: cos = cos + 8*i*0.9
        elif i==4: cos = cos + 8*i*0.8
        elif i==5: cos = cos + 8*i*0.75

    return cos

2015/01/07 03:51

Soori

내림차순으로 sort후에

앞에 값을 뒤의 값으로 빼준다.

5권,3권 < 4권,4권 예외처리한다.

값을 보여준다.

빅오로 O(k) 네요..

def main(book):
    book.sort(reverse=True)

    for i in range(4):
        if book[i]:
            book[i] -= book[i+1]

    nMin = min(book[4], book[2])

    if nMin:
        book[4] -= nMin
        book[2] -= nMin
        book[3] += nMin*2

    printPrice(book)

def printPrice(book):
    PRICES = [1, 0.95, 0.9, 0.8, 0.75]
    total = 0.0
    for i in range(5):
        total += book[i] * (i+1) * 8 * PRICES[i]
    print total

main([2,2,2,1,1])
main([2000,1000,500,10,1])
main([19023126192856123,8012389197123000,9000123000,5000123100,1000])
결과
51.2
26444.0
2.09874289363e+17
[Finished in 0.1s]

2015/03/23 01:20

Starleaguer

// SP_Herry.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//

#include "stdafx.h"
#include<algorithm>
#include<vector>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> vt;
    vt.push_back(2);    vt.push_back(3);    vt.push_back(2);    vt.push_back(1);    vt.push_back(1);
    sort(vt.begin(),vt.end());
    double dDiscountRate[5] = {0.25,0.20,0.10,0.05}; 
    int nBookPrice = 40;
    double  dPrice = 0;
    for(int iter = 0 ; iter< 5 ; iter++)
    {
        dPrice += vt[iter] * nBookPrice * ( 1.0 -  dDiscountRate[iter]);
        for(int i = iter+1 ; i < 5 ; i++)
        {
            vt[i] -= vt[iter];
        }
        nBookPrice-=8;
    }
    printf("total cost : %f EUR",dPrice);
    return 0;
}


2015/04/30 16:52

김 영남

static void exce74()
    {
        int[] books = new int[5],basket;
        int chk = -1,total = 0,indx=0;
        double price = 0;
        Scanner scan = new Scanner(System.in);

        for (int i = 0; i < 5; i++)
        {
            System.out.printf("%d권 구입 수 : ", i + 1);
            books[i] = scan.nextInt();
            total += books[i];
        }

        basket = new int[total];

        while (chk != 0)
        {
            int cnt = 0;
            chk = 0;
            for (int i = 0; i < 5; i++)
            {
                if (books[i] > 0)
                {
                    cnt++;
                    chk++;
                    books[i]--;
                }
            }
            if(chk!=0)
            basket[indx++] = cnt;
        }

        for(int i=1;i<=total/5;i++)
        {
            if(basket[i] == 3)
            {
                basket[0]--;
                basket[i]++;
            }
        }

        for(int i=0;i<=total/5;i++)
        {
            switch(basket[i])
            {
                case 1:
                    price += 8;
                    break;
                case 2:
                    price += (8*2)*0.95;
                    break;
                case 3:
                    price += (8*3)*0.9;
                    break;
                case 4:
                    price += (8*4)*0.8;
                    break;
                case 5:
                    price += (8*5)*0.75;
                    break;
            }
        }

        System.out.println(price);
        scan.close();
    }

5,3 -> 4,4 로 바뀌는 경우 외외에는 한묶음이 많을수록 무조건 더 싸지므로 저 경우를 찾아서 바꿔주는식으로 구하였습니다.

2015/08/20 10:22

조서현

다른 분들 답 보고 깨달았습니다. 4권과 3권 차이였군요!


a = [ 2000, 1000, 500, 10, 1 ]
b = [ 0, 0, 0, 0, 0 , 0 ]  
discount = [ 0, 0, 5, 10, 20, 25 ]  
sum = 0.0

while (True) :  
    cnt = 0
    for i in range(5) :
        if ( a[i] > 0 ) : cnt+=1 ; a[i] -= 1    
    if cnt == 0 : break
    b[cnt] += 1

if ( b[3] > b[5] ) :
    b[3] -= b[5] ; b[4] += 2 * b[5] ; b[5] = 0
else :
     b[4] += 2* b[3] ; b[5]-= b[3] ; b[3] = 0 

for i in range(6) :
    sum += b[i] * i * 8.0 * ( 100.0 - discount[i] ) / 100 

print sum  

2015/09/02 18:04

Kim JungRae

l=list(map(int,input().split()))
l.sort()
l.reverse()
print(l)
m1=l[0]-l[1]
m2=l[1]-l[2]
l[2]
if l[3]+l[4]>=l[2]:
    m4=l[2]
    m5=l[3]+l[4]-l[2]
    m4=m4-m5
else:
    m4=l[3]+l[4]
    m5=0
m3=l[2]-m4-m5
print(m1,m2,m3,m4,m5)
price=m1*8+m2*15.2+m3*21.6+m4*25.6+m5*30
print(price)

2015/09/09 21:38

이 성현

def book_price(book, n, price_table):
    price = 0
    while True:
        if n > 5-book.count(0):
            n = 5-book.count(0)
            if n == 0:
                break
        price += n * 8 * price_table[n]
        for i in range(n):
            book[i] -= 1
        book.sort(reverse=True)
    return price


if __name__ == '__main__':
    discount = {2:0.95, 3:0.9, 4:0.8, 5:0.75}

    num_book = [2, 2, 2, 1, 1]
    num_book.sort(reverse=True)

    n_max = 5-num_book.count(0)
    price_list = [book_price(num_book[:],n,discount) for n in range(2,n_max+1)]

    print('Minimum price is %.2f EUR' % min(price_list))

2015/12/31 22:27

SPJung

  • python으로 작성하였습니다. 큰묶음 우선으로 묶이도록 계산하되, 5권1묶음+3권2묶음 대신 4권 2묶음이 되도록 예외처리 하였습니다.(작은 묶음이 우선 계산되는 경우는 이경우 밖에 없는것 같네요)
salePrices=[8.0,8.0*0.95,8.0*0.9,8.0*0.8,8.0*0.75]

def getBookPrice(books):
    price=0
    cart=[0,0,0,0,0]

    while(True):
        cnt=0

        if(books.count(2)==3 and books.count(1)==2): #5*1,3*2 대신 4*2가 되도록
            cart[3]+=2;books=[0,0,0,0,0]
            break;

        for idx,book in enumerate(books):
            if book!=0:
                books[idx]=book-1
                cnt+=1

        if cnt!=0:
            cart[cnt-1]+=1
        else:
            break


    for idx,cnt in enumerate(cart):
        price+=cnt*(idx+1)*salePrices[idx] 

    return price

# test case
books=[2,2,2,1,1]
books1=[2,2,2,3,4]
books2=[4,4,4,2,2]

print getBookPrice(books)
print getBookPrice(books1)
print getBookPrice(books2)

2016/01/13 10:07

씨니컬우기님

무식무식하게 큐 돌려서 풀었습니다.

copies = map(int, raw_input().split())
q=[[0]+copies]
res=[]
while q:
    tmp = q.pop(0)
    money = tmp[0]
    books = tmp[1:]
    books.sort(reverse=True)
    for n, price in [(1,8.0),(2,15.2),(3,21.6),(4,25.6),(5,30.0)]:
        books_copy = books[:]
        money_copy = money
        if len(books_copy) >= n:
            for i in range(n):
                books_copy[i] -= 1
            while 0 in books_copy : books_copy.remove(0)
            money_copy += price
            if not books_copy : res.append(money_copy)
            elif not [money_copy]+books_copy in q:
                q.append([money_copy]+books_copy)
print min(res)

2016/01/28 19:21

상파

booklist = (raw_input("input the number of books to be bought, each divided by a space only:").split(" ")
result = 0
for i in range(len(booklist)):
    booklist[i]=eval(booklist[i])
while booklist[0]+booklist[1]+booklist[2]+booklist[3]+booklist[4] > 0:
    if booklist.count(0) == 0:
        for k in range(len(booklist)):
            booklist[k]-=1
                result += 8*5*0.75

    if booklist.count(0) == 1:
        for k in range(len(booklist)):
            if booklist[k] != 0:
                booklist[k] -= 1
        result += 8*4*0.80

    if booklist.count(0) == 2:
        for k in range(len(booklist)):
            if booklist[k] != 0:
                booklist[k]-=1
        result += 8*3*0.90

    if booklist.count(0) == 3:
        for k in range(len(booklist)):
            if booklist[k] != 0:
                booklist[k]-=1
        result += 8*2*0.95

    if booklist.count(0) == 4:
        for k in range(len(booklist)):
            if booklist[k] != 0:
                booklist[k]-=1
        result += 8

print result     

하이고..... IDE 하나가 고장이 나서 다른 걸로 하는데 복붙하면 들여쓰기한 게 다 망가진다는 걸 배웠습니다ㅠㅠ 그거 고치느라 한참 걸렸네요 분명 제대로 했는데 계속 에러 나고..... 그래서 복사해서 메모장에 붙여보니까 어떤 건 탭 되어있고 어떤 건 스페이스 되어있고..... 휴..... 그리고 문제에 51.20 이라고 되어있는데, 51.60 아닌가요?ㅠㅠ 그건 문제에 댓글 달았으니 봐주세요..... 그리고 질문 있습니다! 저 북리스트는 장바구니고, 각 원소는 각 시리즈의 구매 수입니다. 결국 장바구니에 하나라도 남은 시리즈가 몇 시리즈 되는지를 조건문으로 나누어서 푼 건데요, 질문은요, 보시면 아시다시피 조건문이 if 하고 if 하고 또 if 하고 이런 식입니다. if 하고 elif 하고 그랬더니 문법 오류라고 뜨더라구요ㅠㅠ 그건 왜 그런거죠? 아시는 분 제발 댓글 달아주세요ㅠㅠ 그리 잘 쓴 코드는 아니지만 그래도 푸는 건 수월했는데 웬 IDE 가 고장나고 옮기는데 형식이 다 깨지고 해서 짜증 이빠이 났네요..... 휴 그래도 첫 레벨4 문제인데 풀게 되어서 기쁩니당 호호 즐코딩!!!!!

2016/02/05 15:27

취미로재미로

아 질문 하나 더 있는데요, for i in booklist: i =+ 1 print booklist 하면 += 1 이 반영이 안되는데요, for i in range(len(booklist)): booklist[i] += 1 print booklist 하면 +=1이 반영이 되네요. 왜 그런거죠? - 취미로재미로, 2016/02/05 15:30
다음과 같은 코드를 생각해봅시다. x = [1] for i in x i =+ 1 이 코드는 다음과 똑 같습니다. x=[1] i=1 i+=1 이렇게 하면 x의 내용이 절대 바뀔 리가 없죠. 일단 이것으로 위의 질문에 대한 답은 되었구요. 한가지 더 말씀드리자면, 좀 다른 경우가 생기는데 이것도 한번 생각해보세요. x=[[1]] for i in x: i[0] += 1 이렇게 하면 x의 내용이 바뀝니다.이것은 파이썬 자료형이 2가지가 있기 때문인데요, 바뀌지 않는 값(숫자, 문자열, 튜플)과 바뀌는 값(바뀌는 3가지를 제외한 모든것)이 할당문("="를 사용하는 문장)에서 일어나는 일이 다르기 때문입니다. 설명이 너무 길어지긴 합니다만, a=1 b=a b=2 a=? 그리고, a=[1] b=a b[0]=2 a=? 이렇게 하면 a의 값은 변할까요? 변하지 않을까요? 직접 테스트해보세요. 파이썬에서 아주 중요하고 꼭 이해하고 넘어가야 할 문제라서, 관련사항을 꼭 찾아보세요. 이거 모르면 프로그래밍 못해요. 디버깅 절대 못합니다. ㅎ - 상파, 2016/02/07 22:46

c 코드로 입력했어요. 51.20 나옵니다. 처음에는 잘못코딩해서 51.60 나왔었어요.

#include <stdio.h>

int main(void)
{
    int aa = 0, bb = 0, cc = 0, dd = 0, ee = 0, ff = 0, gg = 0, hh = 0, ii = 0, e = 0, a = 0, b = 0, f = 0,  arr[10000], arr1[10000], arr4[10000];
    double g = 0.0;

    for(a = 0; a < 5; a++)
    {
        scanf("%d", &arr[a]);
    }
    for(a = 0; a < 5; a++)
    {
        b = b + arr[a];
        arr1[a] = arr[a];
    }
    g = b*8;
    a = 0;
    while(1)
    {
        if(arr1[a] >= 1)
        {
            arr4[bb] = 1;
            bb++;
            aa++;
        }
        else if(arr1[a]==0)
        {
            arr4[bb] = 0;
            aa++;
            bb++;
        }
        else if(arr1[a] < 0)
        {
            arr4[bb] = 0;
            aa++;
            bb++;
        }

        arr1[a] = arr1[a] - 1;
        a++;
        if(a==5)
        {
            a = 0;
            for(cc = bb - 5; cc < bb; cc++)
            {
                dd = dd + arr4[cc];
            }
            if(dd==0)
                break;
            dd = 0;
        }
    }
    for(a = 0; a < bb; a++)
    {
        if(arr4[a]!=0)
        {
            f = f + arr4[a];
        }
        if(a%5==4)
        {
            e = 5 - f;

            if(e==0)
            {
                g = g - 8*5*0.25;
            }
            else if(e==1)
            {
                g = g - 8*4*0.2;
            }
            else if(e==2)
            {
                g = g - 8*3*0.1;
            }
            else if(e==3)
            {
                g = g - 8*2*0.05;
            }
            else if(e==4)
            {
                g = g;
            }
            if(f==3)
            {
                hh++;
            }
            else if(f==5)
            {
                ii++;
            }
            ee++;
            f = 0;
            e = 0;
        }
    }
    if(hh > ii)
    {
        g = g + 8*5*0.25*ii;
        g = g + 8*3*0.1*hh;
        g = g - 2*8*4*0.2*ii;
    }
    else if(hh <= ii)
    {
        g = g + 8*5*0.25*ii;
        g = g + 8*3*0.1*hh;
        g = g - 2*8*4*0.2*hh;
    }
    printf("%f\n", (double) g);
    return 0;
}

2016/02/15 20:05

전승빈

리스트의 리스트 형식으로 카트를 구성하고, 책을 하나씩 넣으면서 (단일 카트 내에는 중복된 책이 들어가지 않도록) 매번 책이 추가될 때마다 최소값이 되는 카트 구성을 찾고, 이 때의 최소값과 카트 구성을 리턴받게 됩니다. 이 과정을 매 책을 추가해가면서 반복합니다.

대신 이 과정은 책들이 정렬되어 있을 때만 올바르게 동작합니다. 따라서 입력받은 책 목록을 정렬한 후에 시행합니다.

def do(xs):
    def compute_price(carts):
        def compute_books(cart):
            discount = (0, 1, 0.95, 0.9, 0.8, 0.75)
            return len(cart) * 8 * discount[len(cart)]
        return sum([compute_books(cart) for cart in carts])


    def find_min_sum(carts, book):
        result = compute_price(carts) + 8
        result_cart = carts + [[book]]
        for i, cart in enumerate(carts):
            if book not in cart:
                _temp_cart = carts[:i] + [cart + [book]] + carts[i+1:]
                _result = compute_price(_temp_cart)
                if _result < result:
                    result = _result
                    result_cart = _temp_cart
        return result, result_cart


    carts = []
    for book in sorted(xs):
        m, carts = find_min_sum(carts, book)
    print(m, carts)

2016/05/23 17:54

룰루랄라

Ruby

discnt = ->pack { [0, 1, 0.95, 0.9, 0.8, 0.75][pack.size] * 8 * pack.size }
price = ->cart { cart.empty? ? 0 : cart.map(&discnt).reduce(:+) }
min_cart = ->cart,book do
  make_cases = ->i,t=cart.dup { t[i]+=[book]; t if t.all? {|_|_.size==_.uniq.size} }
  ((0...cart.size).map(&make_cases).compact << cart+[[book]]).min_by &price
end
min_price = ->books,cart=[],book=books.shift do
  book ? min_price[books, min_cart[cart,book]] : price[cart]
end

Test

no_discnt_cases = [[], [0], [0,0]] 
simple_cases    = [[0,1], [0,2,4]]
several_cases   = [[0,0,1], [0,0,1,1], [0,0,1,2,2,3]]
edge_cases      = [ [0,0,1,1,2,2,3,4],  [0, 0, 0, 0, 0,
                                         1, 1, 1, 1, 1,
                                         2, 2, 2, 2,
                                         3, 3, 3, 3, 3,
                                         4, 4, 4, 4] ]

expect( no_discnt_cases.map(&min_price) ).to eq [8*0, 8*1, 8*2]
expect( simple_cases.map(&min_price) ).to  eq [(8 * 2 * 0.95), (8 * 3 * 0.9)]
expect( several_cases.map(&min_price) ).to eq [(8 * 2 * 0.95) + (8 * 1 * 1.0), 
                                               (8 * 2 * 0.95) * 2,
                                               (8 * 2 * 0.95) + (8 * 4 * 0.8)]
expect( edge_cases.map(&min_price) ).to eq [(8 * 4 * 0.8) * 2, 
                                            (8 * 5 * 0.75) * 3 + 
                                            (8 * 4 * 0.8 ) * 2 ]

Output

p min_price[ [0,0,1,1,2,2,3,4] ] #=> 51.2

2016/07/31 19:17

rk

재귀를 통해 모든 경우의 수 중 최소 값을 구합니다.

제약조건으로 책을 내림차순으로 정렬했다고 가정....

내림차순 정렬까지 추가하기는 손이 가다보니 생략ㅠ,.ㅠ

#include <stdio.h>
#include <stdlib.h>

bool verdict(int book[5]);
void function(int book[5], double sum);

int price = 8;
double min = 1000;
void main() {
    int book[5] = {2,2,2,1,1};
    double value = 0;
    function(book, 0);
    printf("%f", min);

}
void function(int book[5], double sum) {
    double ex_sum = sum;
    double price = 1;
    int copy[5];
    for(int i=0;i<5;i++) 
        copy[i] = book[i];

    for(int i=1;i<6;i++) {
        sum = ex_sum;
        int count = 0;
        for(int j=0;j<5;j++) {
            if(copy[j] > 0)
                count++;
            book[j] = copy[j];
        }

        if(count == 0) {
            if(sum < min)
                min = sum;
            break;
        }
        if(i==1 && count >= 1) {
            price = 1*8;
            int j=0;
            int c=0;
            while(1) {
                if(book[j] > 0) {
                    book[j]--;
                    c++;
                }
                if(c==i) break;
                j++;
            }
        }
        else if(i==2 && count >= 2) {
            price = 2*8*0.95;
            int j=0;
            int c=0;
            while(1) {
                if(book[j] > 0) {
                    book[j]--;
                    c++;
                }
                if(c==i) break;
                j++;
            }
        }
        else if(i==3 && count >= 3) {
            price = 3*8*0.90;
            int j=0;
            int c=0;
            while(1) {
                if(book[j] > 0) {
                    book[j]--;
                    c++;
                }
                if(c==i) break;
                j++;
            }
        }
        else if(i==4 && count >= 4) {
            price = 4*8*0.80;
            int j=0;
            int c=0;
            while(1) {
                if(book[j] > 0) {
                    book[j]--;
                    c++;
                }
                if(c==i) break;
                j++;
            }
        }
        else if(i==5 && count >= 5) {
            price = 5*8*0.75;
            int j=0;
            int c=0;
            while(1) {
                if(book[j] > 0) {
                    book[j]--;
                    c++;
                }
                if(c==i) break;
                j++;
            }
        }
        else
            break;
        sum = sum + price;
        function(book, sum);
    }
}

2017/02/16 16:44

코딩초보

sale = (1, 0.95*2, 0.9*3, 0.8*4, 0.75*5)

inp = {1:2, 2:2, 3:2, 4:1, 5:1}

tmp = max(inp.items(), key = lambda x: x[1])
cart = [[tmp[0]] for _ in range(tmp[1])]
del inp[tmp[0]]

for i,j in inp.items():
    for _ in range(j):
        tmp = [None,1]
        for idx,k in enumerate(cart):
            if i in k: continue
            else:
                if sale[len(k)]-sale[len(k)-1] < tmp[1]:
                    tmp = [idx,sale[len(k)]-sale[len(k)-1]]
        cart[tmp[0]].append(i)

print(cart)
print(sum(sale[len(k)-1]*8 for i in cart))

2018/08/02 22:59

Creator

def tie(books):
    bundles, b5, b3 = [], [], []
    while books:
        bundle = set(books)
        bundles.append(bundle)
        for num in bundle:
            books.remove(num)

        if len(bundle) == 5: b5.append(bundle)
        if len(bundle) == 3: b3.append(bundle)

    for b5, b3 in zip(b5, b3):
        book = (b5 - b3).pop()
        b5.remove(book)
        b3.add(book)

    return bundles


def bill(bundles):
    dc = (0, 0, 0.05, 0.1, 0.2, 0.25)
    total = 0
    for bundle in bundles:
        size = len(bundle)
        bp = 8 * size * (1 - dc[size])
        total += bp
        print(bundle, bp)

    print(total, 'EUR')


books = [1, 1, 2, 2, 3, 3, 4, 5]
bill(tie(books))


2018/09/26 19:43

Noname

def calcPrice(numBooks):
    discountRate = [0,0, 0.05, 0.1, 0.2, 0.25]
    tprice = 0.0
    dn = 0
    while True:
        leftbook = 0
        for i in range(5):            
            if numBooks[i] > 0:
                if dn == 4 and leftbook>0:
                    continue               
                dn += 1
                numBooks[i] -= 1
                if numBooks[i]>0:
                    leftbook += 1
        if dn == 0:
            break
        else:
            tprice += (dn*8*(1-discountRate[dn]))
        dn=0
    return tprice

print('각각의 책 구입 권수를 입력하세요:')
numBooks = [0,0,0,0,0]
numBooks[0] = int(input('the first book: '))
numBooks[1] = int(input('the second book: '))
numBooks[2] = int(input('the third book: '))
numBooks[3] = int(input('the fourth book: '))
numBooks[4] = int(input('the fifth book: '))

print('최저가: ',calcPrice(numBooks),'EUR')

2023/12/04 21:44

insperChoi

목록으로