├── .gitignore ├── LICENSE ├── README.md ├── Untitled Diagram.xml ├── doc └── Chapter6.pdf ├── input ├── knapsack ├── knapsack2.go └── knapsack2_test.go └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # go extra files 2 | .DS_Store 3 | .idea/ 4 | output 5 | 6 | 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matt Schofield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # multiple-knapsack-problem 2 | An implementation of the 0/1 Multiple Knapsack problem. 3 | 4 | The 0-1 Multiple Knapsack Problem (MKP) is: give a set of n items and a set of m knapsacks (m <= n) 5 | 6 | ### build for windowns xp 32bit 7 | 8 | ``` 9 | env GOOS=windows GOARCH=386 go build 10 | ``` 11 | 12 | ### reference 13 | 14 | ``` 15 | ./doc/Chapter6.pdf 16 | ``` 17 | 18 | ### how to use 19 | 20 | 1. change "input" file 21 | ``` 22 | ; lines starting with ; or # are comments 23 | ; knapsack list 24 | ; num weight/size 25 | 2 21000 26 | ; following lines specify list of objects with properties 27 | ; name price/value weight/size 28 | ZM170740765 10180 10180 29 | ZM170840636 6435 6435 30 | ZM170840637 6340 6340 31 | ZM170840804 10100 10100 32 | ZM170840805 10005 10005 33 | ZM170840806 10055 10055 34 | ZM170840807 10940 10940 35 | ZM161240072 1600 1600 36 | ZM170240664 800 800 37 | ZM170840710 9888 9888 38 | ``` 39 | 1. go run main.go 40 | 1. check "output" file 41 | ``` 42 | capacity: 42.000, max: 41.900, num: 5, time: 0 seconds 43 | knap: name(knap-1-21000), capacity(21.000), used(20.995), num(2) 44 | item: name(ZM170840807), weight(10.940), value(10.940) 45 | item: name(ZM170840806), weight(10.055), value(10.055) 46 | knap: name(knap-2-21000), capacity(21.000), used(20.905), num(3) 47 | item: name(ZM170840804), weight(10.100), value(10.100) 48 | item: name(ZM170840805), weight(10.005), value(10.005) 49 | item: name(ZM170240664), weight(0.800), value(0.800) 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /Untitled Diagram.xml: -------------------------------------------------------------------------------- 1 | 5ZlZb+M2EMc/jR9r6Lb1uHGOFmiBRVO0jwJN0RKxFClQlI9++g4tSpZMJnAWduHN+iERZ3iI8/95eHgWrqr9i0R1+YfICZsFXr6fhY+zIPCjMIJ/2nLoLFGadoZC0txUOhle6b/EGD1jbWlOmklFJQRTtJ4aseCcYDWxISnFblptI9h01BoVxDK8YsRs6z80V6Wx+p53cvxKaFGaoZexcawR/lZI0XIz3iwIN8dP565Q35ep35QoF7uRKXyahSsphOqeqv2KMB3bPmxdu+c3vMN7S8LVJQ0WXpIkizjBy2i9TkP8i+lhi1hL+ikcX1Qd+uBAD6ADFB52JVXktUZYe3aAAthKVTEo+fB4jAPRI3lQGqaqC1hUFPcOJcW3Ic664UZw9YwqyjQ+fxOZI46M2bDiR0PDlWBCgokLrt9pQxnrTRB9z0vSY592ZPqpEqnIfmQykXohoiJKHqCK8QZLo9ph4KEr706MxD0i5QiPwYgMl8XQ90kbeDDyXChVYEn1xBWRtaQgTpAwGPwhp1t4LPTjQ9tQTpqmd8F4I6+jgflau2vfIRNauouYMN/IrrGLlWOnZnKOr9SHwYm8KTgwlAVOkDjAGYxXBSe2wFmJqmo5VQdL2IlCOWrKQbuRqB8KOkNrwr6KhioqOPgw0dSCQ8eTQg7+/azCWiglqlGFL4wW2qFE3TFU65et9oVejOZis6GYzNuGyKb7a2E3Ju3CXHOGyvPxc520EsZTOqLIpiNKXFnlBmwkNhttA+EHhewM8UrkFmJ9YY74wVGC2izrRshg+ddy3zVWySKZYuWHl2EV3wCrhYXVn6SpBXeuVC8Q1vrngEqaKGTFcc73TdR5ogo8m6h46SAqugFRSztRwcwkYq6dDISqIJWe+aWbn58ktTXdNCG7dcHLqiFUmfHdO5T+YgJl6Ehzsf8/QZlaUD7SgionlI9kS5io36PyM1Gms53gWS1JBeeTJutsdw7X4nzjvgzsNTRywLW8AVz9aXNE118ElxymXhwcgK20RBB/pMibh77PQxhuJZxf5gpejf8gqSs63/inNl2uU2Gc3IIu++bnN76RCNRusWol+TywYMExqdUkH905KnEanqFinxFDVyK6xWbet2+eXphYO1e5r0gqDrm/1Fe3nzwJDVwVEA2SUT0IJ/d+Towif4KW77p+SG20ett10QottJ74lkrB9T7JSdiXnZ79OxebV8PrXPaqwYjMCxgcds5afUV5K9omwwfM3uPxZji4cf1+/JHpZ2hxjVR2tur5YWzz5jpF3uK6y7fvQp8pRxw7l7uJ+g2EppnDoQm28XPSSjEl6C3tnWR9Zx6y5Hnndn1C+n1loCScHuH8ZWoTETuI8D9MBBRPP64dfaNfMMOn/wA= -------------------------------------------------------------------------------- /doc/Chapter6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzysmail/multiple-knapsack-problem/c8eae18f9b1f564a94005d032096ba66f0caa64a/doc/Chapter6.pdf -------------------------------------------------------------------------------- /input: -------------------------------------------------------------------------------- 1 | ; lines starting with ; or # are comments 2 | ; knapsack list 3 | ; num weight/size 4 | 2 21000 5 | ; following lines specify list of objects with properties 6 | ; name price/value weight/size 7 | ZM170740765 10180 10180 8 | ZM170840636 6435 6435 9 | ZM170840637 6340 6340 10 | ZM170840804 10100 10100 11 | ZM170840805 10005 10005 12 | ZM170840806 10055 10055 13 | ZM170840807 10940 10940 14 | ZM161240072 1600 1600 15 | ZM170240664 800 800 16 | ZM170840710 9888 9888 -------------------------------------------------------------------------------- /knapsack/knapsack2.go: -------------------------------------------------------------------------------- 1 | package knapsack 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "sort" 7 | ) 8 | 9 | var Debug = true 10 | 11 | // A Packable item is one that can be placed in a Knapsack 12 | // It must implement a Weight() and a Value() function in order to determine 13 | // whether or not the item should be packed or not. 14 | type Packable interface { 15 | Name() string 16 | Weight() int64 17 | Value() int64 18 | SetName(string) 19 | SetWeight(int64) 20 | SetValue(int64) 21 | } 22 | 23 | type Knapsackable interface { 24 | Name() string 25 | Weight() int64 26 | Items() []Packable 27 | AddItem(packable Packable) 28 | New() Knapsackable 29 | SetName(string) 30 | SetWeight(int64) 31 | } 32 | 33 | var EPSILON float64 = 0.00000001 34 | 35 | func isFloat64Equals(a, b float64) bool { 36 | if ((a - b) < EPSILON && (b - a) < EPSILON) { 37 | return true 38 | } 39 | return false 40 | } 41 | 42 | func greedys(items []Packable, knaps []Knapsackable, i int, c []int64, z *int64, y []int) { 43 | n := len(items) 44 | for j := 0; j < n; j++ { 45 | item := items[j] 46 | if (y[j] < 0 && item.Weight() <= c[i]) { 47 | y[j] = i 48 | c[i] -= item.Weight() 49 | *z += item.Value() 50 | } 51 | } 52 | } 53 | 54 | func printPackable(items []Packable) { 55 | fmt.Printf("items: %d\n", len(items)) 56 | for _, item := range items { 57 | fmt.Printf("name: %s, weight: %d, value: %d\n", item.Name(), item.Weight(), item.Value()) 58 | } 59 | } 60 | 61 | func MultipleKnapsackProblem(items []Packable, knaps []Knapsackable) (packs []Knapsackable, max int64) { 62 | sort.Slice(knaps, func(i, j int) bool { 63 | return (knaps[i].Weight() < knaps[j].Weight()) 64 | }) 65 | sort.Slice(items, func(i, j int) bool { 66 | pwj := float64(items[j].Value()) / float64(items[j].Weight()) 67 | pwi := float64(items[i].Value()) / float64(items[i].Weight()) 68 | if (isFloat64Equals(pwi, pwj)) { 69 | return items[j].Value() < items[i].Value() 70 | } else { 71 | return pwj < pwi 72 | } 73 | }) 74 | 75 | var z int64 76 | var y []int 77 | 78 | // 1 initial solution 79 | n := len(items) 80 | y = make([]int, n) 81 | for j := 0; j < n; j++ { 82 | y[j] = -1 83 | } 84 | 85 | m := len(knaps) 86 | c := make([]int64, m) 87 | for i := 0; i < m; i++ { 88 | knap := knaps[i] 89 | c[i] = knap.Weight() 90 | greedys(items, knaps, i, c, &z, y) 91 | } 92 | 93 | fmt.Printf("kanpsacks: %d, items: %d\n", m, n) 94 | 95 | if (Debug) { 96 | fmt.Printf("z1: %d, c: %v, y: %v\n", z, c, y) 97 | } 98 | 99 | // 2 rearrangement 100 | z = 0 101 | for i := 0; i < m; i++ { 102 | knap := knaps[i] 103 | c[i] = knap.Weight() 104 | } 105 | 106 | i := 0 107 | for j := n - 1; j >= 0; j-- { 108 | if (y[j] < 0) { 109 | continue 110 | } 111 | item := items[j] 112 | l := -1 113 | for k := i; k < m; k++ { 114 | if (item.Weight() <= c[k]) { 115 | l = k 116 | break 117 | } 118 | } 119 | if (l < 0) { 120 | for k := 0; k < i - 1; k++ { 121 | if (item.Weight() <= c[k]) { 122 | l = k 123 | break 124 | } 125 | } 126 | } 127 | if (l < 0) { 128 | y[j] = -1 129 | } else { 130 | y[j] = l 131 | c[l] -= item.Weight() 132 | z += item.Value() 133 | if (l < m - 1) { 134 | i = l + 1 135 | } else { 136 | i = 0 137 | } 138 | } 139 | } 140 | for i := 0; i < m; i++ { 141 | greedys(items, knaps, i, c, &z, y) 142 | } 143 | if (Debug) { 144 | fmt.Printf("z2: %d, c: %v, y: %v\n", z, c, y) 145 | } 146 | 147 | // 3 first improvement 148 | for j := 0; j < n; j++ { 149 | if (y[j] < 0) { 150 | continue 151 | } 152 | for k := j + 1; k < n; k++ { 153 | if (y[k] >= 0 && y[k] != y[j]) { 154 | itemj := items[j] 155 | itemk := items[k] 156 | var h int 157 | var l int 158 | if (itemj.Weight() >= itemk.Weight()) { 159 | h = j 160 | l = k 161 | } else { 162 | h = k 163 | l = j 164 | } 165 | d := items[h].Weight() - items[l].Weight() 166 | u := -1 167 | var min int64 = math.MaxInt32 168 | for x := 0; x < n; x++ { 169 | if (y[x] < 0 && min > items[x].Weight()) { 170 | min = items[x].Weight() 171 | u = x 172 | } 173 | } 174 | if (u >= 0 && d <= c[y[l]] && (c[y[h]] + d) >= items[u].Weight()) { 175 | var p int64 176 | t := -1 177 | for x := 0; x < n; x++ { 178 | if (y[x] < 0 && items[x].Weight() <= (c[y[h]] + d)) { 179 | if (p < items[x].Value()) { 180 | p = items[x].Value() 181 | t = x 182 | } 183 | } 184 | } 185 | c[y[h]] = c[y[h]] + d - items[t].Weight() 186 | c[y[l]] = c[y[l]] - d 187 | y[t] = y[h] 188 | y[h] = y[l] 189 | y[l] = y[t] 190 | z += items[t].Value() 191 | } 192 | } 193 | } 194 | } 195 | if (Debug) { 196 | fmt.Printf("z3: %d, c: %v, y: %v\n", z, c, y) 197 | } 198 | 199 | // 4 second improvement 200 | for j := n - 1; j >= 0; j-- { 201 | if (y[j] < 0) { 202 | continue 203 | } 204 | item := items[j] 205 | cbar := c[y[j]] + item.Weight() 206 | var ybig []int 207 | for k := 0; k < n; k++ { 208 | if (y[k] < 0 && items[k].Weight() <= cbar) { 209 | ybig = append(ybig, k) 210 | cbar = cbar - items[k].Weight() 211 | } 212 | } 213 | 214 | var sumpk int64 215 | for k := 0; k < len(ybig); k++ { 216 | sumpk += items[ybig[k]].Value() 217 | } 218 | if (sumpk > items[j].Value()) { 219 | for k := 0; k < len(ybig); k++ { 220 | y[ybig[k]] = y[j] 221 | } 222 | c[y[j]] = cbar 223 | y[j] = -1 224 | z = z + sumpk - items[j].Value() 225 | } 226 | } 227 | if (Debug) { 228 | fmt.Printf("z4: %d, c: %v, y: %v\n", z, c, y) 229 | } 230 | 231 | // 5 pack knapsacks 232 | max = z 233 | for i := 0; i < m; i++ { 234 | knap := knaps[i].New() 235 | for j := 0; j < n; j++ { 236 | if (y[j] == i) { 237 | knap.AddItem(items[j]) 238 | } 239 | } 240 | packs = append(packs, knap) 241 | } 242 | return 243 | } 244 | -------------------------------------------------------------------------------- /knapsack/knapsack2_test.go: -------------------------------------------------------------------------------- 1 | package knapsack 2 | 3 | import ( 4 | "testing" 5 | "github.com/stretchr/testify/assert" 6 | ) 7 | 8 | var items []Packable 9 | var knaps []Knapsackable 10 | 11 | 12 | type Item struct { 13 | name string 14 | weight int64 15 | value int64 16 | } 17 | 18 | func (i *Item) Weight() int64 { 19 | return i.weight 20 | } 21 | 22 | func (i *Item) Value() int64 { 23 | return i.value 24 | } 25 | 26 | func (i *Item) Name() string { 27 | return i.name 28 | } 29 | 30 | func (i *Item) SetName(name string) { 31 | i.name = name 32 | } 33 | 34 | func (i *Item) SetWeight(weight int64) { 35 | i.weight = weight 36 | } 37 | 38 | func (i *Item) SetValue(value int64) { 39 | i.value = value 40 | } 41 | 42 | type Knap struct { 43 | name string 44 | weight int64 45 | items []Packable 46 | } 47 | 48 | func (k *Knap) Weight() int64 { 49 | return k.weight 50 | } 51 | 52 | func (k *Knap) Items() []Packable { 53 | return k.items 54 | } 55 | 56 | func (k *Knap) Name() string { 57 | return k.name 58 | } 59 | 60 | func (k *Knap) SetName(name string) { 61 | k.name = name 62 | } 63 | 64 | func (k *Knap) SetWeight(weight int64) { 65 | k.weight = weight 66 | } 67 | 68 | func (k *Knap) AddItem(packable Packable) { 69 | k.items = append(k.items, packable) 70 | } 71 | 72 | func (k *Knap) New() Knapsackable { 73 | kk := Knap{ k.name, k.weight, nil } 74 | return &kk 75 | } 76 | 77 | 78 | func init() { 79 | items = []Packable{ 80 | &Item{ "i1", 40, 80 }, 81 | &Item{ "i2", 10, 20 }, 82 | &Item{ "i3", 40, 60 }, 83 | &Item{ "i4", 30, 40 }, 84 | &Item{ "i5", 50, 60 }, 85 | &Item{ "i6", 50, 60 }, 86 | &Item{ "i7", 55, 65 }, 87 | &Item{ "i8", 25, 25 }, 88 | &Item{ "i9", 40, 30 }, 89 | } 90 | knaps = []Knapsackable{ 91 | &Knap{ "k1", 100, nil }, 92 | &Knap{ "k2", 150, nil }, 93 | } 94 | } 95 | 96 | func Test_MultipleKnapsackProblem(t *testing.T) { 97 | pack, max := MultipleKnapsackProblem(items, knaps) 98 | assert.Equal(t, int64(350), max) 99 | assert.Equal(t, 2, len(pack)) 100 | assert.Equal(t, 3, len(pack[0].Items())) 101 | assert.Equal(t, 4, len(pack[1].Items())) 102 | } 103 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "bufio" 7 | "strings" 8 | "strconv" 9 | "github.com/alexflint/go-arg" 10 | "github.com/logrusorgru/aurora" 11 | "io/ioutil" 12 | "time" 13 | "math" 14 | "github.com/hzysmail/multiple-knapsack-problem/knapsack" 15 | ) 16 | 17 | type Item struct { 18 | name string 19 | weight int64 20 | value int64 21 | } 22 | 23 | func (i *Item) Weight() int64 { 24 | return i.weight 25 | } 26 | 27 | func (i *Item) Value() int64 { 28 | return i.value 29 | } 30 | 31 | func (i *Item) Name() string { 32 | return i.name 33 | } 34 | 35 | func (i *Item) SetName(name string) { 36 | i.name = name 37 | } 38 | 39 | func (i *Item) SetWeight(weight int64) { 40 | i.weight = weight 41 | } 42 | 43 | func (i *Item) SetValue(value int64) { 44 | i.value = value 45 | } 46 | 47 | type Knap struct { 48 | name string 49 | weight int64 50 | items []knapsack.Packable 51 | } 52 | 53 | func (k *Knap) Weight() int64 { 54 | return k.weight 55 | } 56 | 57 | func (k *Knap) Items() []knapsack.Packable { 58 | return k.items 59 | } 60 | 61 | func (k *Knap) Name() string { 62 | return k.name 63 | } 64 | 65 | func (k *Knap) SetName(name string) { 66 | k.name = name 67 | } 68 | 69 | func (k *Knap) SetWeight(weight int64) { 70 | k.weight = weight 71 | } 72 | 73 | func (k *Knap) AddItem(packable knapsack.Packable) { 74 | k.items = append(k.items, packable) 75 | } 76 | 77 | func (k *Knap) New() knapsack.Knapsackable { 78 | kk := Knap{ k.name, k.weight, nil } 79 | return &kk 80 | } 81 | 82 | func readData(fn string) (items []knapsack.Packable, knaps []knapsack.Knapsackable) { 83 | f, err := os.Open(fn) 84 | if err != nil { 85 | fmt.Printf("ERROR: Unable to open file: %v\n", err) 86 | os.Exit(1) 87 | } 88 | fmt.Printf("Reading data from file: %s\n", fn) 89 | defer f.Close() 90 | s := bufio.NewScanner(f) 91 | for s.Scan() { 92 | l := strings.TrimSpace(s.Text()) 93 | if len(l) > 0 && (l[0] == ';' || l[0] == '#') { 94 | continue 95 | } 96 | fields := strings.Fields(l) 97 | if len(fields) == 2 { 98 | num, err := strconv.ParseInt(fields[0], 10, 64) 99 | if err != nil { 100 | fmt.Printf("ERROR: Unable to parse value in:\n>>> %v\n", l) 101 | continue 102 | } 103 | val, err := strconv.ParseInt(fields[1], 10, 64) 104 | if err != nil { 105 | fmt.Printf("ERROR: Unable to parse value in:\n>>> %v\n", l) 106 | continue 107 | } 108 | for i := int64(0); i < num; i++ { 109 | knap := Knap{ name: fmt.Sprintf("knap-%d-%d", i + 1, val), weight: val } 110 | knaps = append(knaps, &knap) 111 | } 112 | continue 113 | } 114 | if len(fields) != 3 { 115 | fmt.Printf("ERROR: Invalid number of fields, must be 3:\n>>> %v\n", l) 116 | continue 117 | } 118 | val, err := strconv.ParseInt(fields[1], 10,64) 119 | if err != nil { 120 | fmt.Printf("ERROR: Unable to parse value in:\n>>> %v\n", l) 121 | continue 122 | } 123 | weight, err := strconv.ParseInt(fields[2], 10, 64) 124 | if err != nil { 125 | fmt.Printf("ERROR: Unable to parse weight in:\n>>> %v\n", l) 126 | continue 127 | } 128 | 129 | item := Item{ name: fields[0], weight: weight, value: val } 130 | items = append(items, &item) 131 | } 132 | 133 | // check we got knapsack capacity from input file 134 | if len(knaps) < 1 { 135 | fmt.Printf("ERROR: Knapsack empty, probably misformed input file\n") 136 | os.Exit(1) 137 | } 138 | 139 | // check we have at least 1 item in store 140 | if len(items) < 1 { 141 | fmt.Printf("ERROR: Empty data, probably misformed input file\n") 142 | os.Exit(1) 143 | } 144 | return 145 | } 146 | 147 | func mockData() (items []knapsack.Packable, knaps []knapsack.Knapsackable) { 148 | //items = []knapsack.Packable{ 149 | // &Item{ "i1", 10, 175 }, 150 | // &Item{ "i2", 9, 90 }, 151 | // &Item{ "i3", 4, 20 }, 152 | // &Item{ "i4", 2, 50 }, 153 | // &Item{ "i5", 1, 10 }, 154 | // &Item{ "i6", 20, 200 }, 155 | //} 156 | //knaps = []knapsack.Knapsackable{ 157 | // &Knap{ "k1", 20, nil }, 158 | //} 159 | 160 | //items = []knapsack.Packable{ 161 | // &Item{ "i1", 3, 5 }, 162 | // &Item{ "i2", 2, 3 }, 163 | // &Item{ "i3", 1, 4 }, 164 | //} 165 | //knaps = []knapsack.Knapsackable{ 166 | // &Knap{ "k1", 5, nil }, 167 | //} 168 | 169 | //items = []knapsack.Packable{ 170 | // &Item{ "i1", 3, 5 }, 171 | // &Item{ "i2", 2, 3 }, 172 | // &Item{ "i3", 1, 4 }, 173 | // &Item{ "i4", 2, 2 }, 174 | //} 175 | //knaps = []knapsack.Knapsackable{ 176 | // &Knap{ "k1", 5, nil }, 177 | //} 178 | 179 | //items = []knapsack.Packable{ 180 | // &Item{ "i1", 3, 5 }, 181 | // &Item{ "i2", 3, 3 }, 182 | //} 183 | //knaps = []knapsack.Knapsackable{ 184 | // &Knap{ "k1", 5, nil }, 185 | // &Knap{ "k2", 5, nil }, 186 | //} 187 | 188 | items = []knapsack.Packable{ 189 | &Item{ "i1", 3, 5 }, 190 | &Item{ "i2", 2, 3 }, 191 | &Item{ "i3", 1, 4 }, 192 | &Item{ "i4", 3, 5 }, 193 | &Item{ "i5", 2, 3 }, 194 | &Item{ "i6", 1, 4 }, 195 | } 196 | knaps = []knapsack.Knapsackable{ 197 | &Knap{ "k1", 5, nil }, 198 | &Knap{ "k2", 5, nil }, 199 | } 200 | return 201 | } 202 | 203 | type Args struct { 204 | FileName string `arg:"help:输入数据文件名"` 205 | Output string `arg:"help:输出数据文件名"` 206 | Divide bool `arg:"help:输出数据是否转成浮点"` 207 | Power uint `arg:"help:转浮点时除以10的乘方数"` 208 | } 209 | 210 | func main() { 211 | var args Args 212 | args.FileName = "input" 213 | args.Output = "output" 214 | args.Divide = true 215 | args.Power = 3 216 | arg.MustParse(&args) 217 | 218 | fmt.Println("start packing...", args) 219 | defer fmt.Println("end packing...") 220 | 221 | // items, knaps := mockData() 222 | items, knaps := readData(args.FileName) 223 | 224 | startTime := time.Now().Unix() 225 | 226 | var max int64 227 | var ret []knapsack.Knapsackable 228 | // ret, max = knapsack.MultiKnapsack(items, knaps) 229 | ret, max = knapsack.MultipleKnapsackProblem(items, knaps) 230 | endTime := time.Now().Unix() 231 | 232 | power := math.Pow(10, float64(args.Power)) 233 | var tmp string 234 | var data []string 235 | var num int 236 | var capacity int64 237 | for _, knap := range ret { 238 | num += len(knap.Items()) 239 | capacity += knap.Weight() 240 | } 241 | if (args.Divide) { 242 | tmp = fmt.Sprintf("capacity: %.3f, max: %.3f, num: %d, time: %d seconds", 243 | float64(capacity) / power, float64(max) / power, num, (endTime - startTime)) 244 | } else { 245 | tmp = fmt.Sprintf("capacity: %d, max: %d, num: %d, time: %d seconds", 246 | capacity, max, num, (endTime - startTime)) 247 | } 248 | fmt.Println(aurora.Red(tmp)) 249 | data = append(data, tmp) 250 | for _, knap := range ret { 251 | var tmpItem []string 252 | var tmpColorItem []string 253 | var tmpWeight int64 254 | var tmpNum int 255 | for _, item := range knap.Items() { 256 | if (args.Divide) { 257 | tmp = fmt.Sprintf(" item: name(%s), weight(%.3f), value(%.3f)", 258 | item.Name(), float64(item.Weight()) / power, float64(item.Value()) / power) 259 | } else { 260 | tmp = fmt.Sprintf(" item: name(%s), weight(%d), value(%d)", item.Name(), item.Weight(), item.Value()) 261 | } 262 | tmpItem = append(tmpItem, tmp) 263 | tmpColorItem = append(tmpColorItem, aurora.Green(tmp).String()) 264 | tmpWeight += item.Value() 265 | tmpNum += 1 266 | } 267 | if (args.Divide) { 268 | tmp = fmt.Sprintf("knap: name(%s), capacity(%.3f), used(%.3f), num(%d)", 269 | knap.Name(), float64(knap.Weight()) / power, float64(tmpWeight) / power, tmpNum) 270 | } else { 271 | tmp = fmt.Sprintf("knap: name(%s), capacity(%d), used(%d), num(%d)", 272 | knap.Name(), knap.Weight(), tmpWeight, tmpNum) 273 | } 274 | data = append(data, tmp) 275 | fmt.Println(aurora.Magenta(tmp)) 276 | data = append(data, tmpItem...) 277 | for _, item := range tmpColorItem { 278 | fmt.Println(item) 279 | } 280 | } 281 | 282 | writeData(data, args.Output) 283 | } 284 | 285 | func writeData(data []string, filename string) { 286 | ioutil.WriteFile(filename, []byte(strings.Join(data, "\n")), os.ModePerm) 287 | } --------------------------------------------------------------------------------