Skip to content

Instantly share code, notes, and snippets.

@kokardy
Created July 21, 2013 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kokardy/6048777 to your computer and use it in GitHub Desktop.
Save kokardy/6048777 to your computer and use it in GitHub Desktop.
薬品の最安値組み合わせを検索するプログラム
package main
/*
最安値薬品組み合わせサーチ
使い方:
minprice.exe -dose [投与量] [規格:価格] [規格:価格]*
*/
import (
"flag"
"fmt"
"log"
"regexp"
"sort"
"strconv"
)
var (
REGEXP_ARG = regexp.MustCompile(`(\d+\.?\d*):(\d+\.?\d*)`)
)
//薬品構造体
//規格量と価格を持つ
type Drug struct {
Amount, Price float64
}
//薬品リスト
//薬品構造体のリストを保持しソート用IFを実装
type DrugList []Drug
func (drugList DrugList) Len() int {
return len(drugList)
}
func (drugList DrugList) Swap(i, j int) {
drugList[i], drugList[j] = drugList[j], drugList[i]
}
func (drugList DrugList) Less(i, j int) bool {
return drugList[i].Amount < drugList[j].Amount
}
func (drugList DrugList) Sort() {
sort.Sort(drugList)
}
func (drugList DrugList) MaxAmount() float64 {
return drugList[drugList.Len()-1].Amount
}
//最安値組み合わせリゾルバ
func (drugList DrugList) Resolver() (f func(float64) ([]int, float64)) {
return drugList.resolver(drugList.Len() - 1)
}
//最安値組み合わせリゾルバ(再起)
func (drugList DrugList) resolver(i int) (f func(float64) ([]int, float64)) {
switch i {
case 0:
//最小規格のみの場合
amount := drugList[i].Amount
price := drugList[i].Price
f = func(dose float64) (l []int, p float64) {
l = make([]int, 1, 1)
l_n := dose / amount
if l_n-float64(int(dose/amount)) > 0.001 {
l_n++
}
l[0] = int(l_n)
p = float64(l[0]) * price
return
}
default:
//n規格以上はn-1規格のリゾルバを使用する
//数学的帰納法的な感じで
prev_resolver := drugList.resolver(i - 1)
amount := drugList[i].Amount
price := drugList[i].Price
f = func(dose float64) (l []int, p float64) {
init_n := dose / amount
if init_n-float64(int(init_n)) > 0.001 {
init_n++
}
p = -1
for n := int(init_n); n >= 0; n-- {
prev_dose := dose - float64(n)*amount
if prev_dose < 0.001 {
prev_dose = 0.0
}
tmp_l, prev_p := prev_resolver(prev_dose)
tmp_p := prev_p + float64(n)*price
//log.Println("p:", tmp_p, "l", append(tmp_l, n))
if p == -1 || p > tmp_p {
p = tmp_p
l = append(tmp_l, n)
}
}
return
}
}
return
}
func main() {
log.Println("start")
var dose float64
flag.Float64Var(&dose, "dose", 0.0, "投与量")
flag.Parse()
args := flag.Args()
drugs := toDrugs(args)
drugs.Sort()
for i, drug := range drugs {
log.Println(i, "amount:", drug.Amount, "price:", drug.Price)
}
resolver := drugs.Resolver()
l, p := resolver(dose)
for i, drug := range drugs {
log.Print(drug.Amount, "*", l[i])
}
//log.Println("list:",l)
log.Println("price", p)
log.Println("end")
}
func toDrugs(args []string) (drugList DrugList) {
drugList = make(DrugList, 0, 5)
for _, arg := range args {
drugList = append(drugList, toDrug(arg))
}
return
}
func toDrug(arg string) (drug Drug) {
mat := REGEXP_ARG.FindStringSubmatch(arg)
//log.Println("arg", arg)
//log.Println("mat", mat)
if len(mat) != 3 {
panic("arg:" + arg + " is not valid")
} else {
amount, err := strconv.ParseFloat(mat[1], 64)
if err != nil {
panic(fmt.Sprint(err, "string:", mat[1], "cannot parsed as float"))
}
price, err := strconv.ParseFloat(mat[2], 64)
if err != nil {
panic(fmt.Sprint(err, "string:", mat[2], "cannot parsed as float"))
}
drug = Drug{amount, price}
}
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment