Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
minimum_vertex_cover.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <vector>
17
18#include "absl/log/check.h"
20
21namespace operations_research {
22
24 const std::vector<std::vector<int>>& left_to_right_arcs, int num_right) {
25 // This algorithm first uses the maximum flow to find a maximum matching. Then
26 // it uses the same method outlined in the proof of Konig's theorem to
27 // transform the maximum matching into a minimum vertex cover.
28 //
29 // More concretely, it uses a DFS starting with unmatched nodes and
30 // alternating matched/unmatched edges to find a minimum vertex cover.
31 SimpleMaxFlow max_flow;
32 const int num_left = left_to_right_arcs.size();
33 std::vector<SimpleMaxFlow::ArcIndex> arcs;
34 for (int i = 0; i < num_left; ++i) {
35 for (const int right_node : left_to_right_arcs[i]) {
36 DCHECK_GE(right_node, num_left);
37 DCHECK_LT(right_node, num_right + num_left);
38 arcs.push_back(max_flow.AddArcWithCapacity(i, right_node, 1));
39 }
40 }
41 std::vector<std::vector<int>> adj_list = left_to_right_arcs;
42 adj_list.resize(num_left + num_right);
43 for (int i = 0; i < num_left; ++i) {
44 for (const int right_node : left_to_right_arcs[i]) {
45 adj_list[right_node].push_back(i);
46 }
47 }
48 const int sink = num_left + num_right;
49 const int source = num_left + num_right + 1;
50 for (int i = 0; i < num_left; ++i) {
51 max_flow.AddArcWithCapacity(source, i, 1);
52 }
53 for (int i = 0; i < num_right; ++i) {
54 max_flow.AddArcWithCapacity(i + num_left, sink, 1);
55 }
56 CHECK(max_flow.Solve(source, sink) == SimpleMaxFlow::OPTIMAL);
57 std::vector<int> maximum_matching(num_left + num_right, -1);
58 for (const SimpleMaxFlow::ArcIndex arc : arcs) {
59 if (max_flow.Flow(arc) > 0) {
60 maximum_matching[max_flow.Tail(arc)] = max_flow.Head(arc);
61 maximum_matching[max_flow.Head(arc)] = max_flow.Tail(arc);
62 }
63 }
64 // We do a DFS starting with unmatched nodes and alternating matched/unmatched
65 // edges.
66 std::vector<bool> in_alternating_path(num_left + num_right, false);
67 std::vector<int> to_visit;
68 for (int i = 0; i < num_left; ++i) {
69 if (maximum_matching[i] == -1) {
70 to_visit.push_back(i);
71 }
72 }
73 while (!to_visit.empty()) {
74 const int current = to_visit.back();
75 to_visit.pop_back();
76 if (in_alternating_path[current]) {
77 continue;
78 }
79 in_alternating_path[current] = true;
80 for (const int j : adj_list[current]) {
81 if (current < num_left && maximum_matching[current] != j) {
82 to_visit.push_back(j);
83 } else if (current >= num_left && maximum_matching[current] == j) {
84 to_visit.push_back(j);
85 }
86 }
87 }
88 std::vector<bool> minimum_vertex_cover(num_left + num_right, false);
89 for (int i = 0; i < num_left; ++i) {
90 if (!in_alternating_path[i]) {
91 minimum_vertex_cover[i] = true;
92 }
93 }
94 for (int i = num_left; i < num_left + num_right; ++i) {
95 if (in_alternating_path[i]) {
96 minimum_vertex_cover[i] = true;
97 }
98 }
99 return minimum_vertex_cover;
100}
101
102} // namespace operations_research
NodeIndex Tail(ArcIndex arc) const
Definition max_flow.cc:44
ArcIndex AddArcWithCapacity(NodeIndex tail, NodeIndex head, FlowQuantity capacity)
Definition max_flow.cc:27
NodeIndex Head(ArcIndex arc) const
Definition max_flow.cc:48
Status Solve(NodeIndex source, NodeIndex sink)
Definition max_flow.cc:60
FlowQuantity Flow(ArcIndex arc) const
Definition max_flow.cc:115
In SWIG mode, we don't want anything besides these top-level includes.
std::vector< bool > BipartiteMinimumVertexCover(const std::vector< std::vector< int > > &left_to_right_arcs, int num_right)