haar_lib/algo/psp.rs
1//! Project Selection Problem
2
3use crate::flow::*;
4
5/// Project Selection Problem
6///
7/// # Problems
8/// - [ARC 085 E - MUL](https://atcoder.jp/contests/arc085/tasks/arc085_c)
9/// - [AOJ 3058 Ghost](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3058)
10/// - [AOJ 2903 Board](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2903)
11/// - [ABC 193 F - Zebraness](https://atcoder.jp/contests/abc193/tasks/abc193_f)
12///
13/// # References
14/// - [https://ferin-tech.hatenablog.com/entry/2019/10/28/燃やす埋める問題](https://ferin-tech.hatenablog.com/entry/2019/10/28/%E7%87%83%E3%82%84%E3%81%99%E5%9F%8B%E3%82%81%E3%82%8B%E5%95%8F%E9%A1%8C)
15/// - [https://kmyk.github.io/blog/blog/2017/12/05/minimum-cut-and-project-selection-problem/](https://kmyk.github.io/blog/blog/2017/12/05/minimum-cut-and-project-selection-problem/)
16///
17/// # Verification
18/// | function | verify |
19/// | -------- | ------ |
20/// | `penalty_if_red` | |
21/// | `penalty_if_blue` | [ARC085 #27489484](https://atcoder.jp/contests/arc085/submissions/27489484) |
22/// | `gain_if_red` | |
23/// | `gain_if_blue` | [ARC085 #27489484](https://atcoder.jp/contests/arc085/submissions/27489484) |
24/// | `penalty_if_red_blue` | |
25/// | `penalty_if_different` | |
26/// | `must_be_red` | |
27/// | `must_be_blue` | |
28/// | `if_red_then_must_be_red` | [ARC085 #27489484](https://atcoder.jp/contests/arc085/submissions/27489484) |
29/// | `gain_if_both_red` | |
30/// | `gain_if_both_blue` | |
31
32#[derive(Clone)]
33pub struct PSP {
34 size: usize,
35 src: usize,
36 sink: usize,
37 edges: Vec<(usize, usize, u64)>,
38 node_count: usize,
39 default_gain: u64,
40}
41
42impl PSP {
43 /// `PSP`を生成する。
44 pub fn new(size: usize) -> Self {
45 Self {
46 size,
47 src: size,
48 sink: size + 1,
49 edges: vec![],
50 node_count: size + 2,
51 default_gain: 0,
52 }
53 }
54
55 /// 頂点iが<font color="red"><b>赤</b></font>ならばcの損失になる。
56 pub fn penalty_if_red(&mut self, i: usize, c: u64) {
57 assert!(i < self.size);
58 self.edges.push((i, self.sink, c));
59 }
60
61 /// 頂点iが<font color="blue"><b>青</b></font>ならばcの損失になる。
62 pub fn penalty_if_blue(&mut self, i: usize, c: u64) {
63 assert!(i < self.size);
64 self.edges.push((self.src, i, c));
65 }
66
67 /// 頂点iが<font color="red"><b>赤</b></font>ならばcの利益を得る。
68 pub fn gain_if_red(&mut self, i: usize, c: u64) {
69 assert!(i < self.size);
70 self.default_gain += c;
71 self.penalty_if_blue(i, c);
72 }
73
74 /// 頂点iが<font color="blue"><b>青</b></font>ならばcの利益を得る。
75 pub fn gain_if_blue(&mut self, i: usize, c: u64) {
76 assert!(i < self.size);
77 self.default_gain += c;
78 self.penalty_if_red(i, c);
79 }
80
81 /// 頂点iが<font color="red"><b>赤</b></font>かつ頂点jが<font color="blue"><b>青</b></font>ならばcの損失となる。
82 pub fn penalty_if_red_blue(&mut self, i: usize, j: usize, c: u64) {
83 assert!(i < self.size && j < self.size);
84 self.edges.push((i, j, c));
85 }
86
87 /// 頂点iとjが異なる色ならばcの損失となる。
88 pub fn penalty_if_different(&mut self, i: usize, j: usize, c: u64) {
89 assert!(i < self.size && j < self.size);
90 self.edges.push((i, j, c));
91 self.edges.push((j, i, c));
92 }
93
94 /// 頂点iは<font color="red"><b>赤</b></font>でなければならない。
95 pub fn must_be_red(&mut self, i: usize) {
96 assert!(i < self.size);
97 self.penalty_if_blue(i, u64::MAX);
98 }
99
100 /// 頂点iは<font color="blue"><b>青</b></font>でなければならない。
101 pub fn must_be_blue(&mut self, i: usize) {
102 assert!(i < self.size);
103 self.penalty_if_red(i, u64::MAX);
104 }
105
106 /// 頂点iが<font color="red"><b>赤</b></font>ならば、頂点jも<font color="red"><b>赤</b></font>でなければならない。
107 pub fn if_red_then_must_be_red(&mut self, i: usize, j: usize) {
108 assert!(i < self.size && j < self.size);
109 self.penalty_if_red_blue(i, j, u64::MAX);
110 }
111
112 /// 頂点iとjがともに<font color="red"><b>赤</b></font>ならばcの利益を得る。
113 pub fn gain_if_both_red(&mut self, i: usize, j: usize, c: u64) {
114 assert!(i < self.size && j < self.size);
115 self.default_gain += c;
116 let w = self.node_count;
117 self.node_count += 1;
118
119 self.edges.push((self.src, w, c));
120 self.edges.push((w, i, u64::MAX));
121 self.edges.push((w, j, u64::MAX));
122 }
123
124 /// 頂点iとjがともに<font color="blue"><b>青</b></font>ならばcの利益を得る。
125 pub fn gain_if_both_blue(&mut self, i: usize, j: usize, c: u64) {
126 assert!(i < self.size && j < self.size);
127 self.default_gain += c;
128 let w = self.node_count;
129 self.node_count += 1;
130
131 self.edges.push((w, self.sink, c));
132 self.edges.push((i, w, u64::MAX));
133 self.edges.push((j, w, u64::MAX));
134 }
135
136 /// must be制約を破った場合、`None`を返す。そうでなければ、利益の最大値を`Some`に包んで返す。
137 pub fn solve<F: MaxFlow<Cap = u64>>(self) -> Option<i64> {
138 let mut f = F::new(self.node_count);
139 for (u, v, c) in self.edges {
140 f.add_edge(u, v, c);
141 }
142
143 let flow = f.max_flow(self.src, self.sink);
144
145 if flow == u64::MAX {
146 None
147 } else {
148 Some(self.default_gain as i64 - flow as i64)
149 }
150 }
151}