problemreductions/models/graph/
maximum_leaf_spanning_tree.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::Problem;
9use crate::types::Max;
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "MaximumLeafSpanningTree",
15 display_name: "Maximum Leaf Spanning Tree",
16 aliases: &[],
17 dimensions: &[
18 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
19 ],
20 module_path: module_path!(),
21 description: "Find spanning tree maximizing the number of leaves",
22 fields: &[
23 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct MaximumLeafSpanningTree<G> {
47 graph: G,
49}
50
51impl<G: Graph> MaximumLeafSpanningTree<G> {
52 pub fn new(graph: G) -> Self {
56 assert!(
57 graph.num_vertices() >= 2,
58 "graph must have at least 2 vertices"
59 );
60 Self { graph }
61 }
62
63 pub fn graph(&self) -> &G {
65 &self.graph
66 }
67
68 pub fn num_vertices(&self) -> usize {
70 self.graph.num_vertices()
71 }
72
73 pub fn num_edges(&self) -> usize {
75 self.graph.num_edges()
76 }
77
78 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
80 is_valid_spanning_tree(&self.graph, config)
81 }
82}
83
84fn is_valid_spanning_tree<G: Graph>(graph: &G, config: &[usize]) -> bool {
88 let n = graph.num_vertices();
89 let edges = graph.edges();
90 if config.len() != edges.len() {
91 return false;
92 }
93
94 let selected_count: usize = config.iter().sum();
96 if selected_count != n - 1 {
97 return false;
98 }
99
100 let mut adj: Vec<Vec<usize>> = vec![vec![]; n];
102 for (idx, &sel) in config.iter().enumerate() {
103 if sel == 1 {
104 let (u, v) = edges[idx];
105 adj[u].push(v);
106 adj[v].push(u);
107 }
108 }
109
110 let mut visited = vec![false; n];
112 let mut queue = std::collections::VecDeque::new();
113 visited[0] = true;
114 queue.push_back(0);
115 while let Some(v) = queue.pop_front() {
116 for &u in &adj[v] {
117 if !visited[u] {
118 visited[u] = true;
119 queue.push_back(u);
120 }
121 }
122 }
123
124 visited.iter().all(|&v| v)
126}
127
128fn count_leaves<G: Graph>(graph: &G, config: &[usize]) -> usize {
130 let n = graph.num_vertices();
131 let edges = graph.edges();
132 let mut degree = vec![0usize; n];
133 for (idx, &sel) in config.iter().enumerate() {
134 if sel == 1 {
135 let (u, v) = edges[idx];
136 degree[u] += 1;
137 degree[v] += 1;
138 }
139 }
140 degree.iter().filter(|&&d| d == 1).count()
141}
142
143impl<G> Problem for MaximumLeafSpanningTree<G>
144where
145 G: Graph + crate::variant::VariantParam,
146{
147 const NAME: &'static str = "MaximumLeafSpanningTree";
148 type Value = Max<usize>;
149
150 fn variant() -> Vec<(&'static str, &'static str)> {
151 crate::variant_params![G]
152 }
153
154 fn dims(&self) -> Vec<usize> {
155 vec![2; self.graph.num_edges()]
156 }
157
158 fn evaluate(&self, config: &[usize]) -> Max<usize> {
159 if !is_valid_spanning_tree(&self.graph, config) {
160 return Max(None);
161 }
162 Max(Some(count_leaves(&self.graph, config)))
163 }
164}
165
166crate::declare_variants! {
167 default MaximumLeafSpanningTree<SimpleGraph> => "1.8966^num_vertices",
168}
169
170#[cfg(feature = "example-db")]
171pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
172 vec![crate::example_db::specs::ModelExampleSpec {
173 id: "maximum_leaf_spanning_tree_simplegraph",
174 instance: Box::new(MaximumLeafSpanningTree::new(SimpleGraph::new(
175 6,
176 vec![
177 (0, 1),
178 (0, 2),
179 (0, 3),
180 (1, 4),
181 (2, 4),
182 (2, 5),
183 (3, 5),
184 (4, 5),
185 (1, 3),
186 ],
187 ))),
188 optimal_config: vec![1, 1, 1, 0, 1, 1, 0, 0, 0],
192 optimal_value: serde_json::json!(4),
193 }]
194}
195
196#[cfg(test)]
197#[path = "../../unit_tests/models/graph/maximum_leaf_spanning_tree.rs"]
198mod tests;