Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
M
mnp-rs
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Package Registry
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Yunxiang Li
mnp-rs
Commits
c9eced8e
Commit
c9eced8e
authored
Dec 10, 2019
by
tleydxdy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
minor improvements, and refactor
parent
84dab23b
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
68 additions
and
53 deletions
+68
-53
src/lib.rs
src/lib.rs
+68
-53
No files found.
src/lib.rs
View file @
c9eced8e
...
...
@@ -16,73 +16,82 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pub
mod
mnp
{
pub
mod
CGA
{
use
std
::
collections
::
BTreeSet
;
// perfect partitions are either all the same, or the difference are 1
fn
is_perfect
(
k
:
usize
,
total
:
usize
,
full
:
&
BTreeSet
<
(
usize
,
Vec
<
usize
>
,
usize
)
>
)
->
bool
{
let
cost
=
full
.iter
()
.next_back
()
.unwrap
()
.0
;
cost
*
k
<=
total
+
k
fn
get_cost
(
sol
:
&
BTreeSet
<
(
usize
,
usize
,
Vec
<
usize
>
)
>
)
->
usize
{
// The cost of the biggest bin is the cost of the solution
sol
.iter
()
.next_back
()
.unwrap
()
.0
}
fn
_
cga
(
fn
is_perfect
(
k
:
usize
,
total
:
usize
,
sol
:
&
BTreeSet
<
(
usize
,
usize
,
Vec
<
usize
>
)
>
)
->
bool
{
// perfect partitions are either all the same, or the difference are 1
get_cost
(
sol
)
*
k
<=
total
+
k
}
fn
_
solve
(
k
:
usize
,
mut
input
:
Vec
<
usize
>
,
total
:
usize
,
mut
part
:
BTreeSet
<
(
usize
,
Vec
<
usize
>
,
usize
)
>
,
mut
part
:
BTreeSet
<
(
usize
,
usize
,
Vec
<
usize
>
)
>
,
mut
best
:
usize
,
)
->
Option
<
BTreeSet
<
(
usize
,
Vec
<
usize
>
,
usize
)
>>
{
)
->
Option
<
BTreeSet
<
(
usize
,
usize
,
Vec
<
usize
>
)
>>
{
match
input
.pop
()
{
Some
(
n
)
=>
{
let
mut
result
=
None
;
//
Create k-1 non-zero bins, first one is created by the wrapper
.
//
If there's still empty bins, use the empty bin first
.
if
part
.len
()
<
k
{
let
mut
new_part
=
part
.clone
();
new_part
.insert
((
n
,
vec!
[
n
],
part
.len
()
));
match
_
cga
(
k
,
input
.clone
(),
total
,
new_part
,
best
)
{
new_part
.insert
((
n
,
part
.len
(),
vec!
[
n
]
));
match
_
solve
(
k
,
input
.clone
(),
total
,
new_part
,
best
)
{
Some
(
sol
)
=>
{
if
is_perfect
(
k
,
total
,
&
sol
)
{
return
Some
(
sol
);
}
best
=
sol
.iter
()
.next_back
()
.unwrap
()
.0
;
best
=
get_cost
(
&
sol
)
;
result
=
Some
(
sol
);
}
None
=>
(),
}
}
let
mut
first_pair
=
part
.iter
()
.next
()
.cloned
()
.unwrap
();
let
cur_min
=
first_pair
.0
;
let
cur_max
=
part
.iter
()
.next_back
()
.unwrap
()
.0
;
let
mut
first_bin
=
part
.iter
()
.next
()
.cloned
()
.unwrap
();
let
cur_max
=
get_cost
(
&
part
);
// If all the bins are the same, just put the next number in the first one.
if
cur_min
==
cur_max
&&
cur_min
+
n
<
best
{
part
.remove
(
&
first_pair
);
first_pair
.1
.push
(
n
);
part
.insert
((
cur_min
+
n
,
first_pair
.1
,
first_pair
.2
));
return
_
cga
(
k
,
input
.clone
(),
total
,
part
,
best
);
// If all the bins are the same, just use the first one.
if
first_bin
.0
==
cur_max
&&
first_bin
.0
+
n
<
best
{
part
.remove
(
&
first_bin
);
first_bin
.0
+=
n
;
first_bin
.2
.push
(
n
);
part
.insert
(
first_bin
);
return
_
solve
(
k
,
input
.clone
(),
total
,
part
,
best
);
}
// If even if we
evenly distribute (total - cur_max) among the rest of the k-1 bins
//
we still won't lower the best, there's no need to search further
.
// If even if we
perfect partition the rest of the k-1 bins we
//
still won't lower the best, we can stop
.
// Use ((a - 1) / b) + 1 for always round up division.
if
((
total
-
cur_max
-
1
)
/
k
)
+
1
<
best
{
// Try putting the next number in all the bins one by one
for
pair
in
part
.iter
()
{
let
cost
=
pair
.0
;
// If improving the best is possible
if
cost
+
n
<
best
{
// Try putting the next item in all the bins one by one,
// for the last i item they only need to be put in the last
// i smallest bins.
for
(
i
,
bin
)
in
part
.iter
()
.enumerate
()
{
if
input
.len
()
<
i
{
break
;
}
// If improving the best is even possible
if
bin
.0
+
n
<
best
{
let
mut
new_part
=
part
.clone
();
let
mut
new_pair
=
new_part
.take
(
pair
)
.unwrap
();
new_pair
.1
.push
(
n
);
new_part
.insert
((
cost
+
n
,
new_pair
.1
,
new_pair
.2
));
match
_
cga
(
k
,
input
.clone
(),
total
,
new_part
,
best
)
{
let
mut
new_bin
=
new_part
.take
(
&
bin
)
.unwrap
();
new_bin
.0
+=
n
;
new_bin
.2
.push
(
n
);
new_part
.insert
(
new_bin
);
match
_
solve
(
k
,
input
.clone
(),
total
,
new_part
,
best
)
{
Some
(
sol
)
=>
{
if
is_perfect
(
k
,
total
,
&
sol
)
{
return
Some
(
sol
);
}
best
=
sol
.iter
()
.next_back
()
.unwrap
()
.0
;
best
=
get_cost
(
&
sol
)
;
result
=
Some
(
sol
);
}
None
=>
(),
...
...
@@ -100,7 +109,7 @@ pub mod mnp {
}
}
pub
fn
cga
(
k
:
usize
,
mut
input
:
Vec
<
usize
>
)
->
Vec
<
Vec
<
usize
>>
{
pub
fn
solve
(
k
:
usize
,
mut
input
:
Vec
<
usize
>
)
->
Vec
<
Vec
<
usize
>>
{
// Deal with dumb inputs.
let
total
=
input
.iter
()
.sum
();
if
k
==
1
||
total
==
0
{
...
...
@@ -115,12 +124,12 @@ pub mod mnp {
// First number always goes in the "first" bin, so don't need to search a tree.
let
mut
part
=
BTreeSet
::
new
();
let
n
=
input
.pop
()
.unwrap
();
part
.insert
((
n
,
vec!
[
n
],
0
));
part
.insert
((
n
,
0
,
vec!
[
n
]
));
_
cga
(
k
,
input
,
total
,
part
,
total
)
_
solve
(
k
,
input
,
total
,
part
,
total
)
.unwrap
()
.iter
()
.map
(|
pair
|
pair
.1
.clone
())
.map
(|
bin
|
bin
.2
.clone
())
.collect
()
}
}
...
...
@@ -131,16 +140,22 @@ mod tests {
#[test]
fn
test_cga
()
{
assert_eq!
(
mnp
::
cga
(
1
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
1
,
3
,
2
]]);
assert_eq!
(
mnp
::
cga
(
2
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
2
,
1
],
vec!
[
3
]]);
assert_eq!
(
mnp
::
cga
(
3
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
1
],
vec!
[
3
],
vec!
[
2
]]);
assert_eq!
(
mnp
::
cga
(
4
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
1
],
vec!
[
3
],
vec!
[
2
]]);
assert_eq!
(
CGA
::
solve
(
1
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
1
,
3
,
2
]]);
assert_eq!
(
CGA
::
solve
(
2
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
3
],
vec!
[
2
,
1
]]);
assert_eq!
(
CGA
::
solve
(
3
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
1
],
vec!
[
3
],
vec!
[
2
]]
);
assert_eq!
(
CGA
::
solve
(
4
,
vec!
[
1
,
3
,
2
]),
vec!
[
vec!
[
1
],
vec!
[
3
],
vec!
[
2
]]
);
assert_eq!
(
mnp
::
cga
(
3
,
vec!
[
8
,
4
,
7
,
5
,
6
]),
vec!
[
vec!
[
8
],
vec!
[
6
,
5
],
vec!
[
7
,
4
]]
CGA
::
solve
(
3
,
vec!
[
8
,
4
,
7
,
5
,
6
]),
vec!
[
vec!
[
8
],
vec!
[
7
,
4
],
vec!
[
6
,
5
]]
);
assert_eq!
(
mnp
::
cga
(
4
,
vec!
[
8
,
4
,
7
,
5
,
6
]),
CGA
::
solve
(
4
,
vec!
[
8
,
4
,
7
,
5
,
6
]),
vec!
[
vec!
[
6
],
vec!
[
7
],
vec!
[
8
],
vec!
[
5
,
4
]]
);
}
...
...
@@ -149,7 +164,7 @@ mod tests {
fn
test_cga_big
()
{
// random big numbers, to avoid perfect partition
assert_eq!
(
mnp
::
cga
(
CGA
::
solve
(
8
,
vec!
[
32525
,
17303
,
7084
,
24185
,
2233
,
23788
,
20717
,
25841
,
14545
,
14807
,
30030
,
...
...
@@ -170,7 +185,7 @@ mod tests {
);
// random small numbers, realistic in some applications
assert_eq!
(
mnp
::
cga
(
CGA
::
solve
(
8
,
vec!
[
13
,
151
,
172
,
121
,
185
,
236
,
237
,
241
,
209
,
215
,
78
,
217
,
54
,
112
,
147
,
189
,
...
...
@@ -182,14 +197,14 @@ mod tests {
]
),
vec!
[
vec!
[
248
,
231
,
209
,
206
,
166
,
163
,
121
,
109
,
78
,
54
,
49
,
27
],
vec!
[
241
,
236
,
217
,
189
,
183
,
151
,
129
,
103
,
85
,
53
,
48
,
26
],
vec!
[
241
,
236
,
215
,
199
,
172
,
162
,
113
,
112
,
78
,
68
,
40
,
25
],
vec!
[
248
,
234
,
208
,
200
,
175
,
152
,
129
,
107
,
78
,
54
,
49
,
27
],
vec!
[
254
,
225
,
209
,
201
,
183
,
147
,
127
,
103
,
85
,
53
,
48
,
26
],
vec!
[
239
,
237
,
220
,
185
,
185
,
151
,
137
,
96
,
80
,
65
,
36
,
31
],
vec!
[
241
,
236
,
217
,
189
,
183
,
150
,
138
,
92
,
92
,
50
,
40
,
32
,
2
],
vec!
[
244
,
235
,
214
,
197
,
182
,
148
,
122
,
112
,
71
,
68
,
47
,
13
,
9
],
vec!
[
248
,
231
,
209
,
207
,
165
,
164
,
120
,
112
,
70
,
68
,
44
,
18
,
6
],
vec!
[
253
,
227
,
208
,
206
,
166
,
163
,
121
,
109
,
77
,
63
,
44
,
22
,
3
]
vec!
[
254
,
225
,
214
,
197
,
182
,
148
,
122
,
112
,
71
,
68
,
47
,
13
,
9
],
vec!
[
253
,
227
,
208
,
207
,
165
,
164
,
120
,
112
,
70
,
68
,
44
,
18
,
6
],
vec!
[
248
,
234
,
208
,
200
,
175
,
152
,
137
,
96
,
80
,
65
,
36
,
31
],
vec!
[
244
,
235
,
209
,
201
,
183
,
147
,
127
,
107
,
77
,
63
,
44
,
22
,
3
],
vec!
[
239
,
237
,
220
,
185
,
185
,
150
,
138
,
92
,
92
,
50
,
40
,
32
,
2
]
]
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment