-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGraph.h
125 lines (113 loc) · 3.05 KB
/
Graph.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#pragma once
#include <cstdint>
#include <memory>
#include <unordered_map>
static constexpr const int64_t kInfFlow = 1LL << 61;
struct Arc {
int64_t from_ = 0;
int64_t to_ = 0;
int64_t low_ = 0;
int64_t high_ = kInfFlow;
int64_t flow_ = 0;
Arc() {}
Arc(const int64_t from, const int64_t to, const int64_t low=0, const int64_t high=kInfFlow)
: from_(from), to_(to), low_(low), high_(high)
{ }
};
using Linkage = std::unordered_map<int64_t, std::unordered_map<int64_t, std::shared_ptr<Arc>>>;
struct Graph {
static constexpr const int64_t INVALID_VERTEX = 0;
Linkage links_;
Linkage backlinks_;
std::shared_ptr<Arc> AddMerge(const Arc& arc) {
auto it = links_.find(arc.from_);
if(it != links_.end()) {
auto jt = it->second.find(arc.to_);
if(jt != it->second.end()) {
// Merge
std::shared_ptr<Arc> ans = jt->second;
ans->flow_ += arc.flow_;
ans->low_ += arc.low_;
ans->high_ += arc.high_;
return ans;
}
}
// Add
return links_[arc.from_][arc.to_] = backlinks_[arc.to_][arc.from_] = std::make_shared<Arc>(arc);
}
std::shared_ptr<Arc> Get(const int64_t from, const int64_t to) {
auto it = links_.find(from);
if(it == links_.end()) {
return nullptr;
}
auto jt = it->second.find(to);
if(jt == it->second.end()) {
return nullptr;
}
return jt->second;
}
std::shared_ptr<Arc> BackGet(const int64_t to, const int64_t from) {
auto it = backlinks_.find(to);
if(it == links_.end()) {
return nullptr;
}
auto jt = it->second.find(from);
if(jt == it->second.end()) {
return nullptr;
}
return jt->second;
}
// Returns true if the arc (and maybe the source vertex) was removed, or false if the edge didn't exist
bool Remove(const int64_t from, const int64_t to) {
auto it = links_.find(from);
if(it == links_.end()) {
return false;
}
auto jt = it->second.find(to);
if(jt == it->second.end()) {
return false;
}
// Remove the arc from the graph
it->second.erase(jt);
if(it->second.empty()) {
// Remove the source vertex if it doesn't have any more outgoing arcs
links_.erase(it);
}
// Erase backlinks
it = backlinks_.find(to);
it->second.erase(from);
if(it->second.empty()) {
backlinks_.erase(it);
}
return true;
}
bool CheckFlow(const int64_t nVertices) {
for(int64_t v=-nVertices; v<=nVertices; v++) {
if(v == 0) {
continue;
}
int64_t inFlow = 0, outFlow = 0;
for(const auto& bl : backlinks_[v]) {
inFlow += bl.second->flow_;
}
for(const auto& fl : links_[v]) {
outFlow += fl.second->flow_;
}
if(inFlow != outFlow) {
return false;
}
}
for(const auto& src : links_) {
for(const auto& dst : src.second) {
std::shared_ptr<Arc> arc = dst.second;
if(arc->flow_ < 0) {
return false;
}
if(arc->flow_ > arc->high_) {
return false;
}
}
}
return true;
}
};