Created
July 21, 2013 14:56
-
-
Save kokardy/6048777 to your computer and use it in GitHub Desktop.
薬品の最安値組み合わせを検索するプログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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