Skip to content

Instantly share code, notes, and snippets.

@gouf
Forked from wonderful-panda/paizahack_lite.md
Last active August 29, 2015 14:04
Show Gist options
  • Save gouf/3d04736aebc906dc3b2b to your computer and use it in GitHub Desktop.
Save gouf/3d04736aebc906dc3b2b to your computer and use it in GitHub Desktop.

paizaオンラインハッカソン lite をPythonで解いてみた.

結果 は0.01秒.

単純に枝刈りしながら深さ優先探索するだけのコードだけど, あらかじめ単価の安い順にソートしておくのと, Solver.least_cost() あたりの処理とで出来るかぎり浅いところで枝刈りされるようにしている.

とはいえ、このコードで TestCase7が0.01秒というのはちょっと速すぎる気がしないでもない.

# -*- coding:utf-8 -*-
from sys import stdin

class Solver(object):
    """
    最良スコアを計算するためのクラス
    
    target      必要な人員数
    companies   下請会社のリスト(単価が安い順にソートされる)
                個々の要素は (単価, 人数, 費用)のタプル
    best        現時点での最良スコア(費用合計の最小値)
    """
    def __init__(self, target, companies):
        self.target = target
        self.companies = sorted(companies)
        self.best = sum(c for (_, m, c) in companies)

    def solve(self):
        """
        最良スコアを計算する
        """
        self._solve(self.target, 0, 0)
        return self.best

    def _solve(self, target, cost, index):
        """
        最良スコア算出用再帰処理

        target      必要な人員数の残り
        cost        現時点での費用合計
        index       次に検討する下請会社のインデックス
        """
        if target <= 0:
            if cost < self.best:
                self.best = cost
            return
        if len(self.companies) <= index:
            return
        if self.best <= cost + self.least_cost(index, target):
            return

        _, m, c = self.companies[index]
        self._solve(target - m, cost + c, index + 1)
        self._solve(target, cost, index + 1)

    def least_cost(self, index, count):
        """
        index番目以降の下請会社からcount人雇うために最低限かかる費用を返す
        """
        ret = 0
        for i in xrange(index, len(companies)):
            unitcost, member, cost = self.companies[i]
            if member < count:
                ret += cost
                count -= member
            else:
                ret += unitcost * count 
                break
        return ret


target = int(stdin.readline())
companies = []
for i in xrange(int(stdin.readline())):
    member, cost = map(int, stdin.readline().split(' '))
    companies.append((float(cost) / member, member, cost))

s = Solver(target, companies)
print s.solve()
# Ref: https://gist.github.com/wonderful-panda/a019722476a5acfd8c6b
class Solver
def initialize(target, companies)
@target = target
@companies = companies.sort
@best = companies.map{|x|
x[0] + x[1] + x[2]
}.inject(:+)
end
def solve
_solve(@target, 0, 0)
@best
end
def _solve(target, cost, index)
if target <= 0
if cost < @best
@best = cost
end
return
end
return if @companies.size <= index
return if @best <= (cost + least_cost(index, target))
_, m, c = @companies[index]
_solve(target - m, cost + c, index + 1)
_solve(target, cost, index + 1)
end
def least_cost(index, count)
ret = 0
for i in (index..@companies.size-1)
unicost, member, cost = @companies[i]
if member < count
ret += cost
count -= member
else
ret += unicost * count
break
end
end
ret
end
end
def input n, res=[]
n == 0 ? res : (input n-1, res << gets.chomp.split(' ').map(&:to_i))
end
target = gets.chomp.to_i
companies = input(gets.chomp.to_i).map{|x|
[x.last.to_f / x.first, x.first, x.last]
}
s = Solver.new(target, companies)
puts s.solve
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment