Commit c9eced8e authored by tleydxdy's avatar tleydxdy

minor improvements, and refactor

parent 84dab23b
......@@ -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]
]
);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment