Advertisement
Guest User

Dinic_AC

a guest
Jan 29th, 2023
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.13 KB | None | 0 0
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. template <typename FlowType>
  5. class FlowGraph {
  6. public:
  7. class Edge {
  8. public:
  9. Edge() = default;
  10.  
  11. Edge(int from, int to, FlowType cap)
  12. : from_(from),
  13. to_(to),
  14. capacity_(cap) {
  15. }
  16.  
  17. [[nodiscard]]
  18. inline FlowType GetPotential() const {
  19. return capacity_ - flow_;
  20. }
  21.  
  22. int from_;
  23. int to_;
  24. FlowType flow_{};
  25. FlowType capacity_;
  26. };
  27.  
  28. FlowGraph(int start,
  29. int terminal,
  30. int vertices,
  31. int edges = -1)
  32. : start_(start),
  33. terminal_(terminal),
  34. n_(vertices),
  35. adj_(vertices),
  36. distance_(vertices),
  37. first_alive_edge_(vertices) {
  38. if (edges != -1) {
  39. edges_.reserve(edges * 2);
  40. }
  41. }
  42.  
  43. inline int AddDirectedEdge(int from, int to, FlowType cap) {
  44. edges_.emplace_back(from, to, cap);
  45. adj_[from].emplace_back(size(edges_) - 1);
  46. edges_.emplace_back(to, from, 0);
  47. adj_[to].emplace_back(size(edges_) - 1);
  48. return adj_[from].back();
  49. }
  50.  
  51. inline int AddBidirectionalEdge(int from, int to, FlowType cap) {
  52. edges_.emplace_back(from, to, cap);
  53. adj_[from].emplace_back(size(edges_) - 1);
  54. edges_.emplace_back(to, from, cap);
  55. adj_[to].emplace_back(size(edges_) - 1);
  56. return adj_[from].back();
  57. }
  58.  
  59. [[nodiscard]]
  60. inline std::optional <Edge> GetEdge(size_t id) {
  61. if (id < size(edges_)) {
  62. return edges_[id];
  63. } else {
  64. return std::nullopt;
  65. }
  66. }
  67.  
  68. /* Computes maximal flow in O(V^2 * E) */
  69. FlowType Dinic() {
  70. FlowType augment;
  71. FlowType max_flow = 0;
  72.  
  73. while (Bfs()) {
  74. while ((augment = Dfs(start_, std::numeric_limits <FlowType>::max())) > 0) {
  75. max_flow += augment;
  76. }
  77. }
  78.  
  79. return max_flow;
  80. }
  81.  
  82. /* Computes maximal flow in O(VE * log(C)), where C is the maximal single edge capacity in the network*/
  83. FlowType ScalingDinic() {
  84. FlowType max_capacity = 0;
  85. for (const Edge& e : edges_) {
  86. max_capacity = std::max(max_capacity, e.GetCapacity());
  87. }
  88.  
  89. while (lower_bound_ * 2 <= max_capacity) {
  90. lower_bound_ *= 2;
  91. }
  92.  
  93. FlowType max_flow = 0;
  94. while (lower_bound_ > 0) {
  95. max_flow += Dinic();
  96. lower_bound_ /= 2;
  97. }
  98.  
  99. return max_flow;
  100. }
  101.  
  102. /* O(E)
  103. * Yields edges which are present in minimal cut between start and terminal and size of minimal cut
  104. * Make sure you've called Dinic() before calling this */
  105. std::pair <std::vector <Edge>, FlowType> MinCut() {
  106. std::vector <char> reachable(n_);
  107.  
  108. auto Dfs = [&](const auto& Self, int node) -> void {
  109. reachable[node] = true;
  110. for (const int& id : adj_[node]) {
  111. Edge& e = edges_[id];
  112. if (!reachable[e.to_] && e.GetPotential() > 0) {
  113. Self(Self, e.to_);
  114. }
  115. }
  116. };
  117.  
  118. Dfs(Dfs, start_);
  119. FlowType min_cut_size = 0;
  120. std::vector <Edge> answer;
  121.  
  122. for (int i = 0; i < size(edges_) / 2; ++i) {
  123. if (reachable[edges_[i * 2].to_] ^ reachable[edges_[i * 2 + 1].to_]) {
  124. if (reachable[edges_[i * 2].to_]) {
  125. answer.push_back(edges_[i * 2 + 1]);
  126. } else {
  127. answer.push_back(edges_[i * 2]);
  128. }
  129. min_cut_size += std::max(edges_[i * 2].flow_, edges_[i * 2 + 1].flow_);
  130. }
  131. }
  132.  
  133. return {answer, min_cut_size};
  134. }
  135.  
  136. /* Decomposes the found flow to paths. Runs in O(VE) */
  137. std::vector <std::pair <std::vector <int>, FlowType>> FlowDecomposition() {
  138. std::vector <int> path;
  139. std::vector <std::pair <std::vector <int>, FlowType>> decomposition;
  140.  
  141. int timer = 0;
  142. std::vector <int> used(n_, -1);
  143. std::fill(begin(first_alive_edge_), end(first_alive_edge_), 0);
  144.  
  145. auto Dfs = [&](const auto& Self, int node, FlowType path_min) -> FlowType {
  146. if (node == terminal_) {
  147. path.emplace_back(node);
  148. return path_min;
  149. }
  150.  
  151. if (used[node] == timer) {
  152. return path_min;
  153. }
  154.  
  155. int id;
  156. FlowType taken;
  157. used[node] = timer;
  158. int& start = first_alive_edge_[node];
  159.  
  160. for (int i = start; i < size(adj_[node]); ++i) {
  161. id = adj_[node][i];
  162. Edge& e = edges_[id];
  163. Edge& e_rev = edges_[id ^ 1];
  164. if (e.flow_ > 0 && (taken = Self(Self, e.to_, std::min(path_min, e.flow_))) > 0) {
  165. path.emplace_back(node);
  166. e.flow_ -= taken;
  167. e_rev.flow_ += taken;
  168. if (e.flow_ == 0) {
  169. start += 1;
  170. }
  171. return taken;
  172. } else {
  173. start += 1;
  174. }
  175. }
  176.  
  177. return 0;
  178. };
  179.  
  180. FlowType taken;
  181. while ((taken = Dfs(Dfs, start_, std::numeric_limits <FlowType>::max())) > 0) {
  182. timer += 1;
  183. std::reverse(begin(path), end(path));
  184. decomposition.emplace_back(path, taken);
  185. path.clear();
  186. }
  187.  
  188. return decomposition;
  189. }
  190.  
  191. private:
  192. bool Bfs() {
  193. std::fill(begin(distance_), end(distance_), -1);
  194.  
  195. distance_[start_] = 0;
  196. auxiliary_queue_.push(start_);
  197. while (!auxiliary_queue_.empty()) {
  198. int node = auxiliary_queue_.front();
  199. auxiliary_queue_.pop();
  200. for (const int& id : adj_[node]) {
  201. Edge& e = edges_[id];
  202. if (distance_[e.to_] == -1
  203. && lower_bound_ <= e.GetPotential()) {
  204. distance_[e.to_] = distance_[node] + 1;
  205. auxiliary_queue_.push(e.to_);
  206. }
  207. }
  208. }
  209.  
  210. if (distance_[terminal_] == -1) {
  211. return false;
  212. }
  213. std::fill(begin(first_alive_edge_), end(first_alive_edge_), 0);
  214. return true;
  215. }
  216.  
  217. FlowType Dfs(int node, FlowType augment) {
  218. if (node == terminal_) {
  219. return augment;
  220. }
  221.  
  222. int id;
  223. FlowType pushed;
  224. int& start = first_alive_edge_[node];
  225.  
  226. for (int i = start; i < size(adj_[node]); ++i) {
  227. id = adj_[node][i];
  228. Edge& e = edges_[id];
  229. Edge& e_rev = edges_[id ^ 1];
  230.  
  231. if (distance_[node] + 1 != distance_[e.to_]
  232. || e.GetPotential() < lower_bound_) {
  233. start += 1;
  234. continue;
  235. }
  236.  
  237. pushed = Dfs(e.to_, std::min(augment, e.GetPotential()));
  238. if (pushed > 0) {
  239. e.flow_ += pushed;
  240. e_rev.flow_ -= pushed;
  241. if (e.GetPotential() < lower_bound_) {
  242. start += 1;
  243. }
  244. return pushed;
  245. } else {
  246. start += 1;
  247. }
  248. }
  249.  
  250. return 0;
  251. }
  252.  
  253. const int start_;
  254. const int terminal_;
  255.  
  256. FlowType lower_bound_ = 1;
  257.  
  258. int n_;
  259. std::vector <Edge> edges_;
  260. std::vector <int> distance_;
  261. std::queue <int> auxiliary_queue_;
  262. std::vector <int> first_alive_edge_;
  263. std::vector <std::vector <int>> adj_;
  264. };
  265.  
  266. void RunCase() {
  267. int n, m, a, b;
  268. cin >> n >> m >> a >> b;
  269.  
  270. vector <vector <char>> grid(n, vector <char>(m));
  271. for (auto& row : grid) {
  272. for (auto& c : row) {
  273. cin >> c;
  274. }
  275. }
  276.  
  277. int vacant = 0;
  278. for (const auto& row : grid) {
  279. for (const auto& c : row) {
  280. if (c == '*') {
  281. vacant += 1;
  282. }
  283. }
  284. }
  285.  
  286. if (2 * b <= a) {
  287. cout << vacant * b * 2 << "\n";
  288. return;
  289. }
  290.  
  291. FlowGraph <int> network(n * m, n * m + 1, n * m + 2, n * m + n * m * 2 + 2);
  292.  
  293. constexpr int dx[] = {-1, 0, 0, 1};
  294. constexpr int dy[] = {0, -1, 1, 0};
  295.  
  296. for (int i = 0; i < n; ++i) {
  297. for (int j = 0; j < m; ++j) {
  298. if (grid[i][j] == '.') {
  299. continue;
  300. }
  301.  
  302. if ((i + j) % 2 == 1) {
  303. network.AddDirectedEdge(i * m + j, n * m + 1, 1);
  304. continue;
  305. }
  306.  
  307. network.AddDirectedEdge(n * m, i * m + j, 1);
  308. for (size_t k = 0; k < 4; ++k) {
  309. int new_i = i + dx[k];
  310. int new_j = j + dy[k];
  311. if (0 <= new_i && new_i <= n - 1
  312. && 0 <= new_j && new_j <= m - 1
  313. && grid[new_i][new_j] != '.') {
  314. network.AddDirectedEdge(i * m + j, new_i * m + new_j, 1);
  315. }
  316. }
  317. }
  318. }
  319.  
  320. int mat = network.Dinic();
  321. assert(mat * 2 <= vacant);
  322. cout << mat * a + b * (vacant - 2 * mat) << "\n";
  323. }
  324.  
  325. int main() {
  326. std::ios_base::sync_with_stdio(false);
  327. std::cin.tie(nullptr);
  328. int tt = 1;
  329. //std::cin >> tt;
  330. while (tt--) {
  331. RunCase();
  332. }
  333. return 0;
  334. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement