mirror of
https://github.com/tig-pool-nk/tig-monorepo.git
synced 2026-02-21 15:31:26 +08:00
Submitted knapsack/knap_one
This commit is contained in:
parent
a2fbd8c435
commit
85c2d38e2c
23
tig-algorithms/src/knapsack/knap_one/README.md
Normal file
23
tig-algorithms/src/knapsack/knap_one/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# TIG Code Submission
|
||||
|
||||
## Submission Details
|
||||
|
||||
* **Challenge Name:** knapsack
|
||||
* **Submission Name:** knap_one
|
||||
* **Copyright:** 2024 VNX
|
||||
* **Identity of Submitter:** VNX
|
||||
* **Identity of Creator of Algorithmic Method:** null
|
||||
* **Unique Algorithm Identifier (UAI):** null
|
||||
|
||||
## License
|
||||
|
||||
The files in this folder are under the following licenses:
|
||||
* TIG Benchmarker Outbound License
|
||||
* TIG Commercial License
|
||||
* TIG Inbound Game License
|
||||
* TIG Innovator Outbound Game License
|
||||
* TIG Open Data License
|
||||
* TIG THV Game License
|
||||
|
||||
Copies of the licenses can be obtained at:
|
||||
https://github.com/tig-foundation/tig-monorepo/tree/main/docs/licenses
|
||||
193
tig-algorithms/src/knapsack/knap_one/mod.rs
Normal file
193
tig-algorithms/src/knapsack/knap_one/mod.rs
Normal file
@ -0,0 +1,193 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use serde_json::{Map, Value};
|
||||
use tig_challenges::knapsack::*;
|
||||
|
||||
|
||||
pub fn solve_challenge(
|
||||
challenge: &Challenge,
|
||||
save_solution: &dyn Fn(&Solution) -> Result<()>,
|
||||
hyperparameters: &Option<Map<String, Value>>,
|
||||
) -> Result<()> {
|
||||
Err(anyhow!("This algorithm is no longer compatible."))
|
||||
}
|
||||
|
||||
// Old code that is no longer compatible
|
||||
#[cfg(none)]
|
||||
mod dead_code {
|
||||
use anyhow::Result;
|
||||
use tig_challenges::knapsack::*;
|
||||
|
||||
pub fn solve_challenge(challenge: &Challenge) -> anyhow::Result<Option<Solution>> {
|
||||
let mut solution = Solution {
|
||||
sub_solutions: Vec::new(),
|
||||
};
|
||||
for sub_instance in &challenge.sub_instances {
|
||||
match solve_sub_instance(sub_instance)? {
|
||||
Some(sub_solution) => solution.sub_solutions.push(sub_solution),
|
||||
None => return Ok(None),
|
||||
}
|
||||
}
|
||||
Ok(Some(solution))
|
||||
}
|
||||
|
||||
pub fn solve_sub_instance(challenge: &SubInstance) -> Result<Option<SubSolution>> {
|
||||
const WAIT_ITERATIONS: usize = 5;
|
||||
const MAX_STAGNANT_ITERATIONS: usize = 5;
|
||||
|
||||
let num_items = challenge.weights.len();
|
||||
let mut selected_items = vec![false; num_items];
|
||||
let mut total_value: i32 = 0;
|
||||
let mut total_weight: u32 = 0;
|
||||
let mut wait_map = vec![None; num_items];
|
||||
let values: Vec<i32> = challenge.values.iter().map(|&v| v as i32).collect();
|
||||
let weights: Vec<f64> = challenge.weights.iter().map(|&w| w as f64).collect();
|
||||
|
||||
let mut items_by_ratio: Vec<(usize, f64)> = (0..num_items)
|
||||
.map(|i| {
|
||||
let adjusted_value = values[i];
|
||||
let ratio = adjusted_value as f64 / weights[i];
|
||||
(i, ratio)
|
||||
})
|
||||
.collect();
|
||||
items_by_ratio.sort_unstable_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
|
||||
let mut interaction_gains = vec![0; num_items];
|
||||
|
||||
let mut iteration_count = 0;
|
||||
let mut stagnant_iterations = 0;
|
||||
let mut max_total_value = total_value;
|
||||
|
||||
loop {
|
||||
iteration_count += 1;
|
||||
|
||||
for entry in &mut wait_map {
|
||||
if let Some(iter) = entry {
|
||||
if *iter <= iteration_count {
|
||||
*entry = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut available_items: Vec<_> = items_by_ratio
|
||||
.iter()
|
||||
.filter(|(i, _)| !selected_items[*i] && wait_map[*i].is_none())
|
||||
.collect();
|
||||
|
||||
let mut improvement_found = false;
|
||||
let mut index = 0;
|
||||
|
||||
while index < available_items.len() {
|
||||
let (i, _) = available_items[index];
|
||||
let individual_value = values[*i];
|
||||
let interaction_gain = interaction_gains[*i];
|
||||
let gain = individual_value + interaction_gain;
|
||||
if gain >= individual_value {
|
||||
selected_items[*i] = true;
|
||||
total_value += gain;
|
||||
total_weight += challenge.weights[*i];
|
||||
|
||||
for j in 0..num_items {
|
||||
interaction_gains[j] += challenge.interaction_values[*i][j];
|
||||
}
|
||||
|
||||
improvement_found = true;
|
||||
available_items.remove(index);
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if !improvement_found {
|
||||
for &(i, _) in &available_items {
|
||||
let new_item_value = values[*i] + interaction_gains[*i];
|
||||
let new_item_weight = challenge.weights[*i];
|
||||
|
||||
if new_item_value <= values[*i] {
|
||||
continue;
|
||||
}
|
||||
|
||||
for j in 0..num_items {
|
||||
if selected_items[j] {
|
||||
let removal_loss = values[j] + interaction_gains[j];
|
||||
if total_value + new_item_value - removal_loss > total_value {
|
||||
for k in 0..num_items {
|
||||
interaction_gains[k] -= challenge.interaction_values[j][k];
|
||||
}
|
||||
selected_items[j] = false;
|
||||
total_value -= removal_loss;
|
||||
total_weight -= challenge.weights[j];
|
||||
|
||||
selected_items[*i] = true;
|
||||
total_value += new_item_value;
|
||||
total_weight += new_item_weight;
|
||||
|
||||
for k in 0..num_items {
|
||||
interaction_gains[k] += challenge.interaction_values[*i][k];
|
||||
}
|
||||
|
||||
wait_map[j] = Some(iteration_count + WAIT_ITERATIONS);
|
||||
improvement_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if improvement_found {
|
||||
break;
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if total_weight > challenge.max_weight {
|
||||
let mut item_loss_ratios = Vec::new();
|
||||
for i in 0..num_items {
|
||||
if selected_items[i] {
|
||||
let loss = values[i] + interaction_gains[i];
|
||||
let ratio = weights[i] / (loss as f64).max(1.0);
|
||||
item_loss_ratios.push((ratio, i));
|
||||
}
|
||||
}
|
||||
item_loss_ratios.sort_unstable_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
|
||||
|
||||
while total_weight > challenge.max_weight {
|
||||
if let Some((_, item)) = item_loss_ratios.pop() {
|
||||
for k in 0..num_items {
|
||||
interaction_gains[k] -= challenge.interaction_values[item][k];
|
||||
}
|
||||
selected_items[item] = false;
|
||||
total_weight -= challenge.weights[item];
|
||||
total_value -= values[item] + interaction_gains[item];
|
||||
wait_map[item] = Some(iteration_count + WAIT_ITERATIONS);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if total_value >= challenge.baseline_value as i32 && total_weight <= challenge.max_weight {
|
||||
let result_items: Vec<usize> = selected_items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, &is_selected)| is_selected)
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
|
||||
return Ok(Some(SubSolution {
|
||||
items: result_items,
|
||||
}));
|
||||
}
|
||||
|
||||
if total_value > max_total_value {
|
||||
max_total_value = total_value;
|
||||
stagnant_iterations = 0;
|
||||
} else {
|
||||
stagnant_iterations += 1;
|
||||
}
|
||||
|
||||
if stagnant_iterations >= MAX_STAGNANT_ITERATIONS {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,7 +116,8 @@
|
||||
|
||||
// c003_a059
|
||||
|
||||
// c003_a060
|
||||
pub mod knap_one;
|
||||
pub use knap_one as c003_a060;
|
||||
|
||||
// c003_a061
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user