# CodeBook team21_34
## TIPS
### 萬用框架
``` C++
#include<bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
// EOF
while (cin >> input) {
//pass
}
return 0;
}
```
---
### 資料型態
``` C++
Bytes Range
整數 int 4 -2*10^9 ~ 2*10^9 (2147483647)
short int 2 -32,768 ~ 32767
long long int 8 -9*10^18 ~ 9*10^18
單精數 float 4 ±3.4×10^-38 ~ ±3.4×10^38 (有效位數 7位)
倍精數 double 8 ±1.7×10^-308 ~ ±1.7×10^308 (有效位數 15位)
計算上 ±1e-14 才比大小
字元 char 1 0 ~ 255 (ASCII碼)
```
---
### MOD
``` C++
(a + b) mod n = [ (a mod n) + (b mod n) ] mod n
(a - b) mod n = [ (a mod n) - (b mod n) ] mod n
(a * b) mod n = [ (a mod n) * (b mod n) ] mod n
(a ^ b) mod n = [ (a mod n) ^ b ] mod n
(a / b) mod n = [ a * ((b mod n) mod^-1 n) ] mod n
```
``` C++
a ≡ b (mod n) & c ≡ d (mod n) <=> a+c ≡ b+d (mod n)
a ≡ b (mod n) & c ≡ d (mod n) <=> ac ≡ bd (mod n)
a ≡ b (mod n) <=> a^k ≡ b^k (mod n)
a ≡ b (mod n) <=> ak ≡ bk (mod n)
```
---
### 小數輸出
``` C++
streamsize ss = cout.precision();
cout << std::setprecision(5) << 12.3456789; // 12.345
cout << setprecision(5) << 12.3; // 12.3
cout << fixed << setprecision(5) << 12.3456789; // 12.34567
cout << fixed << setprecision(5) << 12.3; // 12.30000
cout << resetiosflags(ios::fixed | ios::showpoint) << setprecision(ss); // 重製
```
---
### 字元/字串
``` C++
// 讀取
cin.get(char);
cin.get(char*, num);
cin.getline(char*, num, 'delimiter');
// 在 cin >> 之後,要先讀一次垃圾
getline(cin, string, 'delimiter');
// 判斷
isalnum(char); // EN+NUM
isalpha(char); // EN
islower(char); // EN+NUM
isupper(char); // EN+NUM
isdigit(char); // NUM
// 大小寫轉換
transform(string.begin(), string.end(), dst_string.begin(), toupper/tolower);
// 型態轉換
string -> other : stoi(string) / stoll(string) / stof(string) / stod(string)
other -> string : string = to_string(other);
// 除去陣列裡面重複的字元
v.resize(unique(v.begin(), v.end())-v.begin());
```
---
### 字串分割
#### <string>.find
``` C++=1
#include <iostream>
#include <string>
using namespace std;
int main () {
string s = "scott>=tiger>=mushroom";
string delimiter = ">=";
size_t pos = 0;
string token;
while ((pos = s.find(delimiter)) != string::npos) {
token = s.substr(0, pos);
cout << token << endl;
s.erase(0, pos + delimiter.length());
}
cout << s << endl;
return 0;
}
```
#### <regex>
``` C++=1
#include <iostream>
#include <regex>
using namespace std;
int main () {
string input = "....";
regex rgx("\\s+");
sregex_token_iterator iter(input.begin(), input.end(), rgx, -1);
sregex_token_iterator end;
for (; iter != end; ++iter)
cout << *iter << '\n';
}
```
---
### <sstream>
``` C++
// 型態轉換
stringstream ss;
ss << type1;
ss >> type2;
// 與 getline 同時使用
stringstream ss;
getline(cin , str);
ss << str;
while (ss >> input) {}
// ss 重複使用
ss.clear();
```
#### string → int
``` C++
stringstream int2string;
int n = 12345;
int2string << n;
string s;
int2string >> s;
```
#### int → string
``` C++
stringstream string2int;
string s = "12345";
string2int << s;
int n;
string2int >> n;
```
---
### <algorithm>
``` C++
// data.begin() == arr
// data.end() == arr+n
// 排序
sort(data.begin(), data.end()); // increase
sort(data.begin(), data.end(), greater<>()); // decrease
sort(data.begin(), data.end(), cmp); // customize
// 二分搜,需sort,找 >= find 的位置
lower_bound(data.begin(), data.begin(), find);
// 二分搜,需sort,找 > find 的位置
upper_bound(data.begin(), data.begin(), find);
// 排列所有組合,需sort
do {} while (next_permutation(data.begin(), data.end()));
```
---
### <Containers>
|| vector | deque | stack | queue | set | map |
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| in | push_back / insert | push_back / push_front / insert | push | push | insert | insert|
| access | front / back | front / back | top | front / back | find | operator[ ] / find |
| out | pop_back / erase | pop_back / pop_front / erase | pop | pop| erase | erase |
| size | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| empty | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| clear | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ |
---
### 好用技巧
``` C++
// 2維動態陣列
// int** arr = new int[sizeX][sizeY]
int** aarrry = new int*[sizeX];
for (int i = 0; i < sizeX; ++i) {
arr[i] = new int[sizeY] (NMU);
}
vector<vector<int>> arr(sizeX, vector<int>(sizeY, NUM));
// 比大小
max({num1, num2, ...});
// priority queue
priority_queue<T, vector<T>, cmp> q;
```
#### 自定義比較
``` C++
// 可用在 algorithm.sort, priority_queue
struct compare{
bool operator()(const T& a, const T& b) {
// return a > b; // decrease
// return a < b; // increase
}
} cmp{};
```
#### Class operator overloading
``` C++=1
#include <iostream>
using namespace std;
class Complex {
int real;
int imaginary;
friend istream& operator >> (istream& in, Complex& op) {
in >> op.real >> op.imaginary;
return in;
}
friend ostream& operator << (ostream& out, const Complex& op) {
out << op.real << '+' << op.imaginary << "i";
return out;
}
public:
Complex operator + (const Complex& op2) const {
Complex res;
res.real = real + op2.real;
res.imaginary = imaginary + op2.imaginary;
return res;
}
// Can be used for algorithm sort()
bool operator < (const Complex& op2) const;
};
int main()
{
Complex c1, c2;
cin >> c1 >> c2; // 1 2 3 4
cout << c1 << ',' << c2 << '\n'; // 1+2i, 3+4i
cout << c1 + c2 << '\n'; // 4+6i
return 0;
}
```
---
## CODE
### 質數檢查
```c++=1
#include <iostream>
using namespace std;
int FastPower(long long x, int pow_num, int n) {
// x ^ pow_num % n
x %= n;
long long ans = 1;
for (; pow_num; pow_num >>= 1) {
if (pow_num & 1)
ans = ans * x % n;
x = x * x % n;
}
return ans;
}
bool solve(int num) {
if (num <= 4)
return num == 2 || num == 3;
int d = num - 1, digit = 0;
while (d % 2 == 0) digit++, d /= 2;
for (int a : {2, 7, 61}) {
if (num == a)
return true;
long long temp = FastPower(a, d, num);
if (temp == 1 || temp == num - 1)
continue;
for (int t = 0; t < digit; ++t) {
temp = temp * temp % num;
if (temp == 1)
return false;
if (temp == num - 1)
break;
}
if (temp != num - 1)
return false;
}
return true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int x;
while (cin >> x) {
if (solve(x)) cout << "質數\n";
else cout << "非質數\n";
}
return 0;
}
```
### 找反mod數 (最小正整數)
```c++=1
#include <iostream>
using namespace std;
int gcd(int a, int b, int& x, int& y) {
if (b == 0) {
x = a < 0 ? -1 : 1;
y = 0; // 可以設為任意數
return x * a;
}
int g = gcd(b, a % b, y, x);
y -= a / b * x;
return g;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int a, n;
while (cin >> a >> n) {
if (n == 1) {
if (a == 1) cout << "1\n";
else cout << "No Inverse\n";
continue;
}
// ax + ny = 1 mod n
int x, y;
int ans = gcd(a, n, x, y);
if (ans == 1) {
while (x <= 0) x += n;
cout << x << '\n';
}
else cout << "No Inverse\n";
}
return 0;
}
```
### 費式數列 MOD
``` c++=1
#include <iostream>
#include <array>
using namespace std;
int pisano[1001] = { -1, 1 };
void Initialize() {
// f(x) mod n ≡ f(x mod n') mod n
// n' = pisano
int first, second, third, terms;
for (int i = 2; i <= 1000; ++i) {
first = terms = 0; second = 1;
do {
third = (first + second) % i;
first = second; second = third;
++terms;
} while (first != 0 || second != 1);
pisano[i] = terms;
}
}
unsigned long long FastPower(unsigned long long x, unsigned long long pow_num, int n) {
// x ^ pow_num % n
x %= n;
long long ans = 1;
for (; pow_num; pow_num >>= 1) {
if (pow_num & 1)
ans = ans * x % n;
x = x * x % n;
}
return ans;
}
unsigned long long FastPower(unsigned long long x, unsigned long long pow_num) {
// x ^ pow_num % n
long long ans = 1;
for (; pow_num; pow_num >>= 1) {
if (pow_num & 1)
ans = ans * x;
x = x * x;
}
return ans;
}
void mtx_mul(array<array<unsigned long long, 2>, 2> a,
array<array<unsigned long long, 2>, 2> b,
array<array<unsigned long long, 2>, 2>& res, int mod) {
for (int i{ 0 }; i < 2; ++i)
for (int j{ 0 }; j < 2; ++j) {
res[i][j] = 0;
for (int k{ 0 }; k < 2; ++k) {
res[i][j] += a[i][k] * b[k][j] % mod;
res[i][j] %= mod;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
Initialize();
int t;
cin >> t;
while (t--) {
unsigned long long a, b, n, mod;
array<array<unsigned long long, 2>, 2> A{ 0, 1, 1, 1 }, ans{ 1, 0, 0, 1 };
cin >> a >> b >> mod;
if (pisano[mod] == 1) n = FastPower(a, b);
else n = FastPower(a, b, pisano[mod]);
for (; n; n >>= 1) {
if (n & 1)
mtx_mul(ans, A, ans, mod); // ans *= A
mtx_mul(A, A, A, mod); // A *= A
}
// | ans00 ans01 | ^ n = | x fn |
// | ans10 ans11 | | x x |
cout << ans[0][1] << '\n';
}
return 0;
}
```
### 幾何運算包
``` c++=1
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
class Point {
double x, y;
public:
Point(double x = 0, double y = 0) : x(x), y(y) {}
Point operator+ (const Point& b) const {
return Point(x + b.x, y + b.y);
} // +
Point operator- (const Point& b) const {
return Point(x - b.x, y - b.y);
} // -
Point operator* (double d) const {
return Point(x * d, y * d);
} // *
Point operator/ (double d) const {
return Point(x / d, y / d);
} // /
bool operator < (const Point& b) const {
return (x < b.x) || (x == b.x && y < b.y);
} // <
double dot (const Point& b) const {
// A 在 B 上的投影向量長度
// A 與 B 同向, 內積為正
// A 與 B 同向, 內積為負
// A 與 B 同向, 內積為零
return x * b.x + y * b.y;
} // vector dot
double cross (const Point& b) const {
// A 與 B 形成的平行四邊形面積
// A 到 B 順時針, 外積為負
// A 到 B 逆時針, 外積為正
return x * b.y - y * b.x;
} // vector cross
Point complex_mul (const Point& b) const {
// (a + bi) * (c + di) = (ac – bd) + (bc + ad)i
// = (k1 - k2) + (k1 + k3)i
// k1 = ac + bc = c (a + b)
// k2 = bc + bd = b (c + d)
// k3 = ad - ac = a (d - c)
double k1 = b.x * (x + y);
double k2 = y * (b.x + y);
double k3 = x * (y - b.x);
return Point(k1-k2, k1+k3);
}
double abs2(const Point& b) const {
return pow(x - b.x, 2) + pow(y - b.y, 2);
} // abs2
static bool point_in_segline_1D(const Point& start, const Point& end, const Point& p) {
// 必須要三點共線才能用
// start <- p -> end, dot <= 0
// p -> start -> end, dot > 0
// start -> end -> p, dot > 0
return (start - p).dot(end - p) <= 0;
} // point_in_segline_1D
static bool tripoint_in_sameline_2D(const Point& p1, const Point& p2, const Point& p3) {
// 三點構成面積 == 0, 共線
return (p1 - p3).cross(p2 - p3) == 0;
} // tripoint_in_sameline_2D
static bool point_in_segline_2D(const Point& start, const Point& end, const Point& p) {
// 共線 && 在線段中
return tripoint_in_sameline_2D(start, end, p) && point_in_segline_1D(start, end, p);
} // point_in_segline_2D
static int cross_n0p(const Point& ori, const Point& A, const Point& B) {
// 判斷正負或零
double d = (A - ori).cross(B - ori);
if (d == 0)
return 0;
return d > 0 ? 1 : -1;
} // cross_n0p
static bool seg_intersect(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {
// P3 - P1
// | x |
// P2 - P4
int a123 = cross_n0p(p1, p2, p3);
int a124 = cross_n0p(p1, p2, p4);
int a341 = cross_n0p(p3, p4, p1);
int a342 = cross_n0p(p3, p4, p2);
// 共線
if (a123 == 0 && a124 == 0)
return point_in_segline_1D(p1, p2, p3) || point_in_segline_1D(p1, p2, p4) ||
point_in_segline_1D(p3, p4, p1) || point_in_segline_1D(p3, p4, p2);
// 不共線, <= 0 在不同側
return a123 * a124 <= 0 && a341 * a342 <= 0;
} // seg_intersect
static Point line_intersect_point(const Point& p1, const Point& p2, const Point& p3, const Point& p4) {
double a123 = (p2 - p1).cross(p3 - p1);
double a124 = (p2 - p1).cross(p4 - p1);
return (p4 * a123 - p3 * a124) / (a123 - a124);
} // line_intersect_point
static vector<Point> Graham(vector<Point>& data) {
sort(data.begin(), data.end());
int sz_b = 0;
vector<Point> ans_b;
for (int i = 0; i < data.size(); i++) {
while (sz_b >= 2 && (ans_b[sz_b-1]- ans_b[sz_b-2]).cross(data[i] - ans_b[sz_b-2]) <= 0) {
ans_b.pop_back(), sz_b--;
}
ans_b.push_back(data[i]), sz_b++;
}
int sz_t = 0;
vector<Point> ans_t;
for (int i = data.size()-1; i >= 0; i--) {
while (sz_t >= 2 && (ans_t[sz_t-1] - ans_t[sz_t-2]).cross(data[i] - ans_t[sz_t-2]) <= 0) {
ans_t.pop_back(), sz_t--;
}
ans_t.push_back(data[i]), sz_t++;
}
ans_b.insert(ans_b.end(), ans_t.begin()+1, ans_t.end());
return ans_b;
} // Graham
static double rotatingCaliper(const vector<Point>& data) {
double ans = 0;
for (int i = 0, j = 0; i < data.size(); i++) {
while ( data[i].abs2(data[j]) <= data[i].abs2(data[(j + 1) % data.size()]) )
j = (j + 1) % data.size();
ans = data[i].abs2(data[j]);
}
return sqrt(ans);
} // rotating
};
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
Point p1(5, 6);
Point p2(3, 4);
cout << p1.dot(p2) << '\n'; // 39
cout << p1.cross(p2) << '\n'; // 2
vector<Point> data = { Point(5, 2), Point(4, 5), Point(2, 7), Point(2, 0), Point(1, 4) };
vector<Point> ans = Point::Graham(data);
vector<Point> data2 = { Point(1, 4) };
vector<Point> ans2 = Point::Graham(data2);
double ans3 = Point::rotatingCaliper(data);
return 0;
} // main
```
### 酷酷的線段樹和
``` c++=1
#include <bits/stdc++.h>
#define forn(i, n) for (int i = 0; i < int(n); i++)
using namespace std;
const int N = 200 * 1000 + 13;
int n;
long long T;
int a[N];
int f[N];
void upd(int x){
for (int i = x; i < N; i |= i + 1)
++f[i];
}
int get(int x){
int res = 0;
for (int i = x; i >= 0; i = (i & (i + 1)) - 1)
res += f[i];
return res;
}
int main() {
scanf("%d%lld", &n, &T);
forn(i, n)
scanf("%d", &a[i]);
vector<long long> sums(1, 0ll);
long long pr = 0;
forn(i, n){
pr += a[i];
sums.push_back(pr);
}
sort(sums.begin(), sums.end());
sums.resize(unique(sums.begin(), sums.end()) - sums.begin());
long long ans = 0;
pr = 0;
upd(lower_bound(sums.begin(), sums.end(), 0ll) - sums.begin());
forn(i, n){
pr += a[i];
int npos = upper_bound(sums.begin(), sums.end(), pr - T) - sums.begin();
ans += (i + 1 - get(npos - 1));
int k = lower_bound(sums.begin(), sums.end(), pr) - sums.begin();
upd(k);
}
printf("%lld\n", ans);
return 0;
}
```
### SGT shiung0123 Template
```c++=1
template <class T>
class SGT {
int n;
vector<T> tree;
int root() { return 1; }
int left_child(int tree_index) { return 2 * tree_index; }
int right_child(int tree_index) { return 2 * tree_index + 1; }
unsigned power2ceil(unsigned n) {
// smallest power of 2 >= n
n -= 1;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
} // power2ceil
T merge(const T &x, const T &y) {
return x + y;
} // merge
// [il, ir)
void build(const vector<T> &input, int il, int ir, int tree_index) {
if (ir - il == 1) tree[tree_index] = input[il];
else {
int im = (il + ir) / 2;
build(input, il, im, left_child(tree_index));
build(input, im, ir, right_child(tree_index));
tree[tree_index] =
merge(tree[left_child(tree_index)], tree[right_child(tree_index)]);
}
} // build
void modify(const int &target_index, const T &value, int il, int ir, int tree_index) {
if (ir - il == 1) tree[tree_index] = value;
else {
int im = (il + ir) / 2;
// left
if (target_index < im) modify(target_index, value, il, im, left_child(tree_index));
// right
else modify(target_index, value, im, ir, right_child(tree_index));
tree[tree_index] =
merge(tree[left_child(tree_index)], tree[right_child(tree_index)]);
}
} // set
T query(const int &target_l, const int &target_r, int il, int ir, int tree_index) {
if (target_l == il && target_r == ir) return tree[tree_index];
int im = (il + ir) / 2;
// left
if (target_r <= im) return query(target_l, target_r, il, im, left_child(tree_index));
// right
else if (target_l >= im) return query(target_l, target_r, im, ir, right_child(tree_index));
// cross
else return merge(
query(target_l, im, il, im, left_child(tree_index)),
query(im, target_r, im, ir, right_child(tree_index))
);
} // sum
public:
SGT(const vector<T>& input) {
n = input.size();
tree.resize(power2ceil(n)*2);
build(input, 0, n, root());
} // SGT
// target index start from 0
void modify(const int &target_index, const T &value) {
modify(target_index, value, 0, n, root());
} // set
// target index start from 0
T query(const int &target_l, const int &target_r) {
return query(target_l, target_r, 0, n, root());
} // sum
};
```
### Graph Template
```c++=1
// #pragma warning(disable:4996)
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <queue>
#include <iomanip>
#include <algorithm>
#include <tuple>
#define INT_MAX 2147483647
using namespace std;
class cmp {
public:
bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
// return a < b; // decrease
return a.second > b.second; // increase
}
};
class Graph_adj {
private:
int v_num;
vector< list<pair<int, int>> > AdjList;
vector<int> color; // 0:未走訪, 1:走訪中, 2:走訪完畢
vector<int> distance;
vector<int> discover;
vector<int> finish;
vector<int> predecessor;
vector<int> size;
vector<int> dep;
vector<int> low;
vector<int> head;
vector<int> heavy;
vector<pair<int, int>> i2bi;
vector<vector<int>> bi2i;
void printData(const vector<int>& data, string str) {
cout << str << ":\n";
for (int i = 0; i < v_num; i++) {
cout << setw(4) << i;
}
cout << '\n';
for (int i = 0; i < v_num; i++) {
cout << setw(4) << data[i];
}
cout << '\n';
} // printData
void printData2D(const vector<vector<int>>& data, string str) {
cout << str << ":\n";
for (int i = 0; i < v_num; i++) {
for (int j = 0; j < v_num; j++) {
cout << data[i][j] << ' ';
}
cout << '\n';
}
cout << '\n';
} // printData
public:
Graph_adj() :v_num(0) {};
Graph_adj(int N) :v_num(N) {
AdjList.resize(v_num);
};
void AddEdgeList(int from, int to, int weight = 1, bool undirected = false) {
AdjList[from].push_back(make_pair(to, weight));
if (undirected) AdjList[to].push_back(make_pair(from, weight));
} // AddEdgeList
void ConnectedBFS(int Start) {
queue<int> q;
if (color[Start] == 0) {
color[Start] = 1; // 走訪中
distance[Start] = 0; // 起始點距離為0
predecessor[Start] = -1; // 起始點沒有父節點
q.push(Start);
while (!q.empty()) {
int cur = q.front();
for (auto& next : AdjList[cur]) {
if (color[next.first] == 0) {
color[next.first] = 1; // 走訪中
distance[next.first] = distance[cur] + 1; // 距離為cur+1
predecessor[next.first] = cur; // 父節點為cur
q.push(next.first);
}
}
color[cur] = 2; // 走訪完畢
q.pop();
} // while queue not empty
} // connected BFS end
} // ConnectedBFS
void BFS(int Start) {
color.resize(v_num, 0); // 走訪狀態
distance.resize(v_num, v_num + 1); // 與Start的距離
predecessor.resize(v_num, -1); // 紀錄父節點
ConnectedBFS(Start);
// 避免不連通的清況
for (int i = 0; i < v_num; i++) {
ConnectedBFS(i);
} // for all
printData(color, "color");
printData(distance, "distance");
printData(predecessor, "predecessor");
} // BFS
void ConnectedDFS(int cur, int& time) {
color[cur] = 1; // 走訪中
discover[cur] = ++time; // 紀錄發現時間
for (auto& next : AdjList[cur]) {
if (color[next.first] == 0) {
predecessor[next.first] = cur; // 父節點為cur
ConnectedDFS(next.first, time);
}
}
finish[cur] = ++time; // 紀錄完成時間
color[cur] = 2; // 走訪完畢
} // DFSVisit
void DFS(int Start) {
color.resize(v_num, 0); // 走訪狀態
discover.resize(v_num, 0); // 開始走訪時間
finish.resize(v_num, 0); // 完成走訪時間
predecessor.resize(v_num, -1); // 父節點
int time = 0;
if (color[Start] == 0)
ConnectedDFS(Start, time);
// 避免不連通的清況
for (int i = 0; i < v_num; i++) {
if (color[i] == 0)
ConnectedDFS(i, time);
} // for all
printData(color, "color");
printData(discover, "discover");
printData(finish, "finish");
printData(predecessor, "predecessor");
} // DFS
void DFS_order(vector<int> Start) {
color.resize(v_num, 0); // 走訪狀態
discover.resize(v_num, 0); // 開始走訪時間
finish.resize(v_num, 0); // 完成走訪時間
predecessor.resize(v_num, -1); // 父節點
int time = 0;
for (auto i : Start) {
if (color[i] == 0)
ConnectedDFS(i, time);
} // by order
// 避免不連通的清況
for (int i = 0; i < v_num; i++) {
if (color[i] == 0)
ConnectedDFS(i, time);
} // for all
printData(color, "color");
printData(discover, "discover");
printData(finish, "finish");
printData(predecessor, "predecessor");
} // DFS
int CollapsingFind(int cur) {
if (predecessor[cur] == -1) return cur;
else {
predecessor[cur] = CollapsingFind(predecessor[cur]);
return predecessor[cur];
}
} // CollapsingFind
void SetCollapsing() {
for (int i = 0; i < v_num; i++) {
CollapsingFind(i);
} // for all
int count = 0;
size.resize(v_num, 0);
for (int i = 0; i < v_num; i++) {
if (predecessor[i] == -1) count++, size[i]++;
else size[predecessor[i]]++;
}
cout << count << ' ' << *max_element(size.begin(), size.end()) << '\n';
} // SetCollapsing
Graph_adj GraphTranspose() {
Graph_adj gT(v_num);
for (int i = 0; i < v_num; i++) {
for (auto& next : AdjList[i]) {
gT.AddEdgeList(next.first, i);
}
} // for all
return gT;
} // GraphTranspose
vector<int> getDecreaseFinish() {
vector<pair<int, int>> temp;
temp.reserve(v_num);
for (int i = 0; i < v_num; i++) {
temp.push_back(make_pair(finish[i], i));
} // for all
sort(temp.begin(), temp.end(), greater<>());
vector<int> f;
f.reserve(v_num);
for (auto i : temp)
f.push_back(i.second);
printData(f, "finish order");
return f;
} // getDecreaseFinish
void MST_Prims(int Start) {
color.resize(v_num, 0); // 走訪狀態
distance.resize(v_num, INT_MAX); // 與Start的距離
predecessor.resize(v_num, -1); // 父節點
priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> q;
if (color[Start] == 0) {
color[Start] = 1; // 走訪中
distance[Start] = 0; // 起始點距離為0
predecessor[Start] = -1; // 起始點沒有父節點
q.push(make_pair(Start, 0));
while (!q.empty()) {
pair<int, int> cur = q.top();
q.pop();
if (color[cur.first] != 2) {
for (auto& next : AdjList[cur.first]) {
if (color[next.first] != 2 && next.second < distance[next.first]) {
color[next.first] = 1; // 走訪中
distance[next.first] = next.second; // 最短路徑為
predecessor[next.first] = cur.first; // 父節點為cur
q.push(make_pair(next.first, distance[next.first]));
}
}
color[cur.first] = 2; // 走訪完畢
} // not visited
} // while queue not empty
}
printData(color, "color");
printData(distance, "distance");
printData(predecessor, "predecessor");
/*
for (int i = 0; i < v_num; i++)
if (predecessor[i] != -1)
cout << predecessor[i] << '-' << distance[i] << '-' << i << '\n';
*/
} // MST_Prims
void SSSP_BF(int Start) {
distance.resize(v_num, INT_MAX); // 與Start的距離
predecessor.resize(v_num, -1); // 父節點
distance[Start] = 0; // 起始點距離為0
predecessor[Start] = -1; // 起始點沒有父節點
vector<bool> inqueue1(v_num, false), inqueue2(v_num, false);
queue<int> q1, q2; // 只處理有被relax的點,q1本輪更新,q2下輪更新
q1.push(Start);
inqueue1[Start] = true;
for (int i = 0; i < v_num; i++) {
while (!q1.empty()) {
int cur = q1.front();
q1.pop(), inqueue1[cur] = false;
for (auto& next : AdjList[cur]) {
if (distance[next.first] > distance[cur] + next.second) { // 可以進行relax
distance[next.first] = distance[cur] + next.second; // 最短路徑為
predecessor[next.first] = cur; // 父節點為cur
if (!inqueue2[next.first]) { // 放進q2,給下輪更新
q2.push(next.first);
inqueue2[next.first] = true;
}
}
}
} // while queue not empty
q1.swap(q2), inqueue1.swap(inqueue2);
} // at most v_num-1 edges
if (!q1.empty()) cout << "negative cycle exists";
printData(distance, "distance");
printData(predecessor, "predecessor");
/*
int End = v_num - 1;
for (int i = End; i != Start; i = predecessor[i]) {
cout << i << ' ';
} cout << Start << '\n';
*/
} // SSSP_BF
void SSSP_Dijkstra(int Start) {
color.resize(v_num, 0); // 走訪狀態
distance.resize(v_num, INT_MAX); // 與Start的距離
predecessor.resize(v_num, -1); // 父節點
priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> q;
if (color[Start] == 0) {
color[Start] = 1; // 走訪中
distance[Start] = 0; // 起始點距離為0
predecessor[Start] = -1; // 起始點沒有父節點
q.push(make_pair(Start, 0));
while (!q.empty()) {
pair<int, int> cur = q.top();
q.pop();
if (color[cur.first] != 2) {
for (auto& next : AdjList[cur.first]) {
if (distance[next.first] > distance[cur.first] + next.second) {
color[next.first] = 1; // 走訪中
distance[next.first] = distance[cur.first] + next.second; // 最短路徑為
predecessor[next.first] = cur.first; // 父節點為cur
q.push(make_pair(next.first, distance[next.first]));
}
}
color[cur.first] = 2; // 走訪完畢
} // not visited
} // while queue not empty
}
printData(color, "color");
printData(distance, "distance");
printData(predecessor, "predecessor");
/*
int End = v_num - 1;
for (int i = End; i != Start; i = predecessor[i]) {
cout << i << ' ';
} cout << Start << '\n';
*/
} // SSSP_BF
void FloydWarshall() {
vector<vector<int>> distance2D(v_num, vector<int>(v_num, INT_MAX));
vector<vector<int>> predecessor2D(v_num, vector<int>(v_num, -1));
for (int i = 0; i < v_num; i++) {
distance2D[i][i] = 0;
for (auto& next : AdjList[i]) {
distance2D[i][next.first] = next.second;
predecessor2D[i][next.first] = i;
}
}
for (int k = 0; k < v_num; k++) { // 增加 k-th 點
for (int i = 0; i < v_num; i++) { // 跑過所有 i to j
for (int j = 0; j < v_num; j++) {
if (distance2D[i][k] != INT_MAX && distance2D[k][j] != INT_MAX &&
distance2D[i][j] > distance2D[i][k] + distance2D[k][j]) {
distance2D[i][j] = distance2D[i][k] + distance2D[k][j];
predecessor2D[i][j] = predecessor2D[k][j];
}
}
}
}
printData2D(distance2D, "distance");
printData2D(predecessor2D, "predecessor");
/*
int Start = 0;
int End = v_num - 1;
while (predecessor2D[Start][End] != -1) {
cout << End << ' ';
End = predecessor2D[Start][End];
} cout << Start << '\n';
*/
} // FloydWarshall
// 限用在無向圖
void ConnectedTreeDFS(int cur, int& deep, vector<int>& ap, vector<pair<int, int>>& bridge) {
int child = 0;
low[cur] = dep[cur] = ++deep; // 紀錄當前深度
for (auto& next : AdjList[cur]) {
if (next.first == predecessor[cur]) continue; // 是父節點
if (dep[next.first] == 0) { // 還沒走過
child++;
predecessor[next.first] = cur; // 父節點為cur
ConnectedTreeDFS(next.first, deep, ap, bridge);
low[cur] = min(low[cur], low[next.first]); // 能到達的最小深度
if (low[next.first] >= dep[cur]) { // child能到達的最小深度 >= cur
if (predecessor[cur] != -1) ap.emplace_back(cur);
if (low[next.first] > dep[cur]) bridge.emplace_back(cur, next.first);
}
}
else low[cur] = min(low[cur], dep[next.first]); // 有一條back edge
}
if (predecessor[cur] == -1 && child > 1) ap.emplace_back(cur);
--deep; // 回到先前深度
} // DFSVisit
void DFS_tree(int Start) {
predecessor.resize(v_num, -1); // 父節點
dep.resize(v_num, 0); // dfs tree 深度
low.resize(v_num, INT_MAX); // 先往子孫走,再通過不超過一次的 back edge,
// 所能達到的節點的最小深度
vector<int> ap;
vector<pair<int, int>> bridge;
int deep = 0;
if (dep[Start] == 0)
ConnectedTreeDFS(Start, deep, ap, bridge);
// 避免不連通的清況
for (int i = 0; i < v_num; i++) {
if (dep[i] == 0)
ConnectedTreeDFS(i, deep, ap, bridge);
} // for all
printData(predecessor, "predecessor");
printData(dep, "dep");
printData(low, "low");
cout << "ap:\n";
for (auto& i : ap) cout << i << ' ';
cout << "\nbridge:\n";
for (auto& i : bridge) cout << i.first << ',' << i.second << '\n';
} // DFS_tree
// 限用在無向圖
int ConnectedHeavyDFS(int cur, int& deep, long long dis) {
dep[cur] = ++deep; // 紀錄當前深度
distance[cur] = dis;
int max = 0; // 此鏈最大長度
int total = 1; // 此點(包含)以下的總結點數
for (auto& next : AdjList[cur]) {
if (next.first == predecessor[cur]) continue; // 是父節點
if (dep[next.first] == 0) { // 還沒走過
predecessor[next.first] = cur; // 父節點為cur
int next_total = ConnectedHeavyDFS(next.first, deep, dis + next.second); // 取得子節點的總數
if (next_total > max) { // 選出最重的子點
max = next_total, heavy[cur] = next.first; // 紀錄最重的資訊
}
total += next_total;
}
}
deep--; // 回到先前深度
return total;
} // ConnectedHeavyDFS
void ConnectedHeadDFS(int cur, int head_index) {
head[cur] = head_index;
for (auto& next : AdjList[cur]) {
if (next.first == predecessor[cur]) continue; // 是父節點
if (next.first == heavy[cur])
ConnectedHeadDFS(next.first, head_index); // 走比較重的那側
else ConnectedHeadDFS(next.first, next.first); // 走比較輕的那側
}
} // ConnectedHeadDFS(decompose)
void HLD(int Start) { // Heavy-Light Decomposition
predecessor.resize(v_num, -1); // 父節點
dep.resize(v_num, 0); // dfs tree 深度
heavy.resize(v_num, -1); // 最重的子點代號
head.resize(v_num, -1); // 每條鍊的初始點
distance.resize(v_num, -1); // 距離
int deep = 0;
int dis = 0;
ConnectedHeavyDFS(Start, deep, dis);
ConnectedHeadDFS(Start, Start);
// printData(predecessor, "predecessor");
// printData(dep, "dep");
// printData(distance, "distance");
// printData(heavy, "heavy");
// printData(head, "head");
} // HLD
int LCA(int n1, int n2) {
while (head[n1] != head[n2]) { // 兩條鏈的起始點不同
// 找較深的鏈,到其上一條鏈
if (dep[head[n1]] > dep[head[n2]]) n1 = predecessor[head[n1]];
else n2 = predecessor[head[n2]];
if (n1 == -1 || n2 == -1) return -1; // 找不到
}
// n1 和 n2 在同一條鏈,選深度較淺的
if (dep[n1] < dep[n2]) return n1;
else return n2;
} // LCA
// 限用在無向圖
bool BFS_bi() {
color.resize(v_num, -1); // 塗色狀態
for (int Start = 0; Start < v_num; Start++) {
if (color[Start] == -1) {
queue<int> q;
int c = 0; // 色(0, 1)
color[Start] = c; // 上色
q.push(Start);
while (!q.empty()) {
int cur = q.front();
q.pop();
c = color[cur]; // 父點的色
for (auto& next : AdjList[cur]) {
if (color[next.first] == -1) { // 未塗色
color[next.first] = !c; // 上色
q.push(next.first);
}
else if (color[next.first] == c)
return false; // 與父點同色
}
} // while queue not empty
} // not visited
} // for all
return true;
} // ConnectedBFS_bi
tuple<int,int,vector<list<int>>> GetBIG() {
i2bi.resize(v_num);
bi2i.resize(2, vector<int>());
for (int i = 0; i < v_num; i++) {
i2bi[i].first = color[i];
i2bi[i].second = bi2i[color[i]].size();
bi2i[color[i]].push_back(i);
}
vector<list<int>> result;
result.resize(bi2i[0].size());
for (int cur = 0; cur < v_num; cur++) {
if (i2bi[cur].first) continue;
for (auto& next : AdjList[cur]) {
result[i2bi[cur].second].push_back(i2bi[next.first].second);
}
}
return make_tuple(bi2i[0].size(), bi2i[0].size(), result);
} // GetBIG
void GetMatch(vector<pair<int, int>> result) {
for (auto& i : result) {
cout << bi2i[0][i.first] << ' '
<< bi2i[1][i.second] << '\n';
}
} // GetMatch
};
class BipGraph {
int L_num, R_num;
vector< list<int> > AdjList;
vector<int> pairL2R;
vector<int> pairR2L;
vector<int> distance;
public:
BipGraph() :L_num(0), R_num(0) {};
BipGraph(int L, int R) :L_num(L), R_num(R) {
AdjList.resize(L);
};
BipGraph(tuple<int, int, vector<list<int>>>& g) {
L_num = get<0>(g);
R_num = get<1>(g);
AdjList = get<2>(g);
};
void AddEdgeList(int from, int to) {
AdjList[from].push_back(to);
} // AddEdgeList
// 限用在2分無向圖
bool HopcroftKarp_BFS() {
queue<int> q;
for (int i = 0; i < L_num; i++) {
// 如果未被配對到,可以做為起點
if (pairL2R[i] == L_num) {
distance[i] = 0; // 距離為0
q.push(i); // 放進Q準備BFS
}
// 已被配對過
else distance[i] = INT_MAX; // 距離為最大值
} // init BFS
// 建立一個虛擬的點,假裝已經被配對過
// pairR2L 未配對到,會指向這個點
// 當此值被修改時,表示找到第一個 aug path
// 因此也表示[目前最小 BFS 深度],初值為最大值
distance[L_num] = INT_MAX;
while (!q.empty()) {
int cur = q.front();
q.pop();
// 比[目前最小 BFS 深度]來的小
if (distance[cur] < distance[L_num]) {
for (auto& next : AdjList[cur]) {
// 這個點已被配對過,且在此輪還沒有走訪過
if (distance[pairR2L[next]] == INT_MAX) {
distance[pairR2L[next]] = distance[cur] + 1; // 紀錄這個點的距離,給 DFS 走訪用
q.push(pairR2L[next]); // 可以繼續 BFS
}
}
}
} // while queue not empty
// 如果[目前最小 BFS 深度]不是INT_MAX,表示有 aug path
if (distance[L_num] != INT_MAX) return true;
else return false;
} // HopcroftKarp_BFS
bool HopcroftKarp_DFS(int cur) {
if (cur == L_num) return true; // 找到一個未配對的點,存在aug path
else {
for (auto& next : AdjList[cur]) {
if (distance[pairR2L[next]] == distance[cur] + 1 && // 找到 BFS 留下的記號
HopcroftKarp_DFS(pairR2L[next])) { // aug path 還存在
pairL2R[cur] = next; // 紀錄 L2R
pairR2L[next] = cur; // 紀錄 R2L
return true; // 存在aug path
}
}
// 找不到一個未配對的點 (原本存在,被用掉了)
distance[cur] = INT_MAX; // 覆蓋掉 BFS 的資訊
return false; // 不存在aug path
}
} // HopcroftKarp_DFS
vector<pair<int, int>> HopcroftKarp() {
// 初值為 L_num 表示沒有配對對象
pairL2R.resize(L_num, L_num);
pairR2L.resize(R_num, L_num);
// 紀錄 left 點 BFS 的距離,初值為 0 (right 不算)
// L_num+1 因為有包含一個虛擬的點(index = L_num),未配對前都指向他
distance.resize(L_num + 1, 0);
// 由 BFS 紀錄 distance,DFS 根據 distance 找到配對點
// 若 BFS() = true,表示有 aug path
while (HopcroftKarp_BFS()) {
for (int i = 0; i < L_num; i++) {
if (pairL2R[i] == L_num) // 沒有配對過
HopcroftKarp_DFS(i); // 且有 aug path 存在 (有可能被其他用掉)
}
}
// make pair
vector<pair<int, int>> result;
result.reserve(min(L_num, R_num));
for (int i = 0; i < L_num; i++) {
if (pairL2R[i] != L_num)
result.push_back(make_pair(i, pairL2R[i]));
}
return result;
} // HopcroftKarp
};
class Address {
public:
int x;
int y;
Address() :x(-1), y(-1) {}
Address(int a, int b) :x(a), y(b) {}
Address operator + (const Address& op2) const {
Address res;
res.x = x + op2.x;
res.y = y + op2.y;
return res;
}
Address operator - (const Address& op2) const {
Address res;
res.x = x - op2.x;
res.y = y - op2.y;
return res;
}
bool operator == (const Address& op2) const {
return (x == op2.x && y == op2.y);
}
friend ostream& operator << (ostream& out, const Address& op) {
out << '(' << setw(2) << op.x << ',' << setw(2) << op.y << ')';
return out;
}
};
class Node {
public:
int color; // 0:未走訪, 1:走訪中, 2:走訪完畢
int state; // -1:不能走, 0:可以走
int distance;
int discover;
int finish;
Address predecessor;
int size;
Node() {
color = false;
state = -1;
distance = INT_MAX;
discover = 0;
finish = 0;
predecessor = Address();
};
};
class Graph_map {
private:
int x, y; // will add border (+2)
Node** mapp;
Address around_4[4] =
{ Address(-1,0), Address(0,1), Address(1,0), Address(0,-1) }; // 順時針
Address around_8[8] =
{ Address(-1,0), Address(-1,1), Address(0,1), Address(1,1),
Address(1,0), Address(1,-1), Address(0,-1), Address(-1,-1) }; // 順時針
public:
Graph_map(int row, int column) :x(row + 2), y(column + 2) {
mapp = new Node * [x];
for (int i = 0; i < x; i++)
mapp[i] = new Node[y];
};
void readMap(bool include_broder) {
char input;
int state;
if (include_broder) {
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
cin >> input;
if (input == '#') mapp[i][j].state = -1;
else mapp[i][j].state = 0;
}
}
} // include_broder
else { // uninclude_broder
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
cin >> input;
if (input == '#') mapp[i][j].state = -1;
else mapp[i][j].state = 0;
}
}
} // uninclude_broder
} // readMap
void printMap(bool predecessor = false, bool distance = false, bool discover_finish = false) {
int n = 0;
if (distance) n += 2;
if (predecessor) n += 2;
if (discover_finish) n += 7;
cout << setw(2) << ' ';
for (int j = 0; j < y; j++)
cout << setw(n) << j << ' ';
cout << '\n';
for (int i = 0; i < x; i++) {
cout << setw(2) << i;
for (int j = 0; j < y; j++) {
if (mapp[i][j].state == 0) {
if (predecessor) {
Address cur(i, j);
cur = mapp[i][j].predecessor - cur;
if (cur == Address(-1, 0)) cout << "↑";
else if (cur == Address(0, 1)) cout << "→";
else if (cur == Address(1, 0)) cout << "↓";
else if (cur == Address(0, -1)) cout << "←";
else cout << " ";
} // predecessor
if (distance) {
cout << setw(2) << mapp[i][j].distance;
} // distance
if (discover_finish) {
cout << '(' << setw(2) << mapp[i][j].discover
<< ',' << setw(2) << mapp[i][j].finish << ')';
} // discover_finish
if (!(predecessor | distance | discover_finish)) cout << ' ';
cout << ' ';
}
else {
cout << setw(n) << '#' << ' ';
}
}
cout << '\n';
}
} // printMap
void ConnectedBFS(Address Start) {
queue<Address> q;
if (mapp[Start.x][Start.y].state == 0 &&
mapp[Start.x][Start.y].color == 0) {
mapp[Start.x][Start.y].color = 1; // 走訪中
mapp[Start.x][Start.y].distance = 0; // 起始點距離為0
mapp[Start.x][Start.y].predecessor = Address(-1, -1); // 起始點沒有父節點
q.push(Address(Start.x, Start.y));
while (!q.empty()) {
Address cur = q.front();
for (auto next : around_4) {
next = cur + next;
if (mapp[next.x][next.y].state == 0 &&
mapp[next.x][next.y].color == 0) {
mapp[next.x][next.y].color = 1; // 走訪中
mapp[next.x][next.y].distance =
mapp[cur.x][cur.y].distance + 1; // 距離為cur+1
mapp[next.x][next.y].predecessor = cur; // 父節點為cur
q.push(next);
}
}
mapp[cur.x][cur.y].color = 2; // 走訪完畢
q.pop();
} // while queue not empty
} // connected BFS end
} // ConnectedBFS
void BFS(Address Start) {
ConnectedBFS(Start);
// 避免不連通的清況
for (int i = 1; i < x - 1; i++) {
for (int j = 1; j < y - 1; j++) {
ConnectedBFS(Address(i, j));
} // for all
} // for all
// printMap();
} // BFS
void DFS_recursion(Address cur, int& time) {
mapp[cur.x][cur.y].color = 1; // 走訪中
mapp[cur.x][cur.y].discover = ++time; // 紀錄發現時間
for (auto next : around_4) {
next = cur + next;
if (mapp[next.x][next.y].state == 0 &&
mapp[next.x][next.y].color == 0) {
mapp[next.x][next.y].color = 1; // 走訪中
mapp[next.x][next.y].predecessor = cur; // 父節點為cur
DFS_recursion(next, time);
}
}
mapp[cur.x][cur.y].finish = ++time; // 紀錄完成時間
mapp[cur.x][cur.y].color = 2; // 走訪完畢
} // DFSVisit
void DFS(Address Start) {
int time = 0;
if (mapp[Start.x][Start.y].state == 0 &&
mapp[Start.x][Start.y].color == 0)
DFS_recursion(Start, time);
// 避免不連通的清況
for (int i = 1; i < x - 1; i++) {
for (int j = 1; j < y - 1; j++) {
if (mapp[i][j].state == 0 &&
mapp[i][j].color == 0)
DFS_recursion(Address(i, j), time);
} // for all
} // for all
// printMap();
} // DFS
};
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
// http://alrightchiu.github.io/SecondRound/mu-lu-yan-suan-fa-yu-zi-liao-jie-gou.html
// https://hackmd.io/@nckuacm/NCKU-AdvCP-2021-Materials/https%3A%2F%2Fhackmd.io%2F%40XDEv11%2FNCKU-AdvCP-2021-Graph3#2021-Week12---Graph-BCC-SCC-LCA
// BFS
Graph_adj g1(9);
g1.AddEdgeList(0, 1); g1.AddEdgeList(0, 2); g1.AddEdgeList(0, 3);
g1.AddEdgeList(1, 0); g1.AddEdgeList(1, 4);
g1.AddEdgeList(2, 0); g1.AddEdgeList(2, 4); g1.AddEdgeList(2, 5); g1.AddEdgeList(2, 6); g1.AddEdgeList(2, 7);
g1.AddEdgeList(3, 0); g1.AddEdgeList(3, 7);
g1.AddEdgeList(4, 1); g1.AddEdgeList(4, 2); g1.AddEdgeList(4, 5);
g1.AddEdgeList(5, 2); g1.AddEdgeList(5, 4);
g1.AddEdgeList(6, 2); g1.AddEdgeList(6, 7);
g1.AddEdgeList(7, 2); g1.AddEdgeList(7, 3); g1.AddEdgeList(7, 6);
g1.AddEdgeList(8, 5); g1.AddEdgeList(8, 6);
g1.BFS(0);
// DFS
Graph_adj g2(8);
g2.AddEdgeList(0, 1); g2.AddEdgeList(0, 2);
g2.AddEdgeList(1, 3);
g2.AddEdgeList(2, 1); g2.AddEdgeList(2, 5);
g2.AddEdgeList(3, 4); g2.AddEdgeList(3, 5);
g2.AddEdgeList(5, 1);
g2.AddEdgeList(6, 4); g2.AddEdgeList(6, 7);
g2.AddEdgeList(7, 6);
g2.DFS(0);
// TopologicalSort
g2.getDecreaseFinish();
// SCC
Graph_adj g3(9);
g3.AddEdgeList(0, 1);
g3.AddEdgeList(1, 2); g3.AddEdgeList(1, 4);
g3.AddEdgeList(2, 0); g3.AddEdgeList(2, 3); g3.AddEdgeList(2, 5);
g3.AddEdgeList(3, 2);
g3.AddEdgeList(4, 5); g3.AddEdgeList(4, 6);
g3.AddEdgeList(5, 4); g3.AddEdgeList(5, 6); g3.AddEdgeList(5, 7);
g3.AddEdgeList(6, 7);
g3.AddEdgeList(7, 8);
g3.AddEdgeList(8, 6);
g3.DFS(0);
Graph_adj g4 = g3.GraphTranspose();
vector<int> finish = g3.getDecreaseFinish();
g4.DFS_order(finish);
g4.SetCollapsing();
// Graph_map BFS
/* n = 9
#########
#.......#
#.#####.#
#.......#
##.#.####
#..#.#..#
#.##.##.#
#.......#
#########
*/
Graph_map g5(7, 7);
g5.readMap(true);
g5.BFS(Address(1, 1));
g5.printMap(true, true, false);
// Graph_map DFS
/* n = 9
#########
#.......#
#.#####.#
#.......#
##.#.####
#..#.#..#
#.##.##.#
#.......#
#########
*/
Graph_map g6(7, 7);
g6.readMap(true);
g6.DFS(Address(1, 1));
g6.printMap(true, false, true);
// MST
Graph_adj g7(7);
g7.AddEdgeList(0, 1, 5); g7.AddEdgeList(0, 5, 3);
g7.AddEdgeList(1, 0, 5); g7.AddEdgeList(1, 2, 10); g7.AddEdgeList(1, 4, 1); g7.AddEdgeList(1, 6, 4);
g7.AddEdgeList(2, 1, 10); g7.AddEdgeList(2, 3, 5); g7.AddEdgeList(2, 6, 8);
g7.AddEdgeList(3, 2, 5); g7.AddEdgeList(3, 4, 7); g7.AddEdgeList(3, 6, 9);
g7.AddEdgeList(4, 1, 1); g7.AddEdgeList(4, 3, 7); g7.AddEdgeList(4, 5, 6); g7.AddEdgeList(4, 6, 2);
g7.AddEdgeList(5, 0, 3); g7.AddEdgeList(5, 4, 6);
g7.AddEdgeList(6, 1, 4); g7.AddEdgeList(6, 2, 8); g7.AddEdgeList(6, 3, 9); g7.AddEdgeList(6, 4, 2);
g7.MST_Prims(2);
// SSSP Bellman-Ford 可負weigh, 可負weight cycle
Graph_adj g8(6);
g8.AddEdgeList(0, 1, 5);
g8.AddEdgeList(1, 4, -4); g8.AddEdgeList(1, 2, 6);
g8.AddEdgeList(2, 4, -3); g8.AddEdgeList(2, 5, -2);
g8.AddEdgeList(3, 2, 4);
g8.AddEdgeList(4, 3, 1); g8.AddEdgeList(4, 5, 6);
g8.AddEdgeList(5, 0, 3); g8.AddEdgeList(5, 1, 7);
g8.SSSP_BF(0);
// SSSP Dijkstra 不可負weigh, 不可負weight cycle
Graph_adj g9(6);
g9.AddEdgeList(0, 1, 8); g9.AddEdgeList(0, 5, 1);
g9.AddEdgeList(1, 0, 3); g9.AddEdgeList(1, 2, 1);
g9.AddEdgeList(2, 0, 5); g9.AddEdgeList(2, 3, 2); g9.AddEdgeList(2, 4, 2);
g9.AddEdgeList(3, 1, 4); g9.AddEdgeList(3, 2, 6); g9.AddEdgeList(3, 4, 7); g9.AddEdgeList(3, 5, 3);
g9.AddEdgeList(5, 3, 2); g9.AddEdgeList(5, 4, 8);
g9.SSSP_Dijkstra(0);
// ALL SSSP FloydWarshall 可負weigh, 不可負weight cycle
Graph_adj g10(4);
g10.AddEdgeList(0, 1, 2); g10.AddEdgeList(0, 2, 6); g10.AddEdgeList(0, 3, 8);
g10.AddEdgeList(1, 2, -2); g10.AddEdgeList(1, 3, 3);
g10.AddEdgeList(2, 0, 4); g10.AddEdgeList(2, 3, 1);
g10.FloydWarshall();
// DFS_tree
Graph_adj g11(6);
g11.AddEdgeList(0, 1, 1, true);
g11.AddEdgeList(1, 2, 1, true); g11.AddEdgeList(1, 3, 1, true);
g11.AddEdgeList(2, 3, 1, true);
g11.AddEdgeList(3, 4, 1, true); g11.AddEdgeList(3, 5, 1, true);
g11.AddEdgeList(4, 5, 1, true);
g11.DFS_tree(0);
// DFS_heavy_light
Graph_adj g12(14);
g12.AddEdgeList(0, 1, 1, true); g12.AddEdgeList(1, 2, 1, true); g12.AddEdgeList(2, 4, 1, true); g12.AddEdgeList(4, 5, 1, true);
g12.AddEdgeList(2, 3, 1, true);
g12.AddEdgeList(1, 6, 1, true);
g12.AddEdgeList(0, 7, 1, true); g12.AddEdgeList(7, 8, 1, true); g12.AddEdgeList(8, 9, 1, true);
g12.AddEdgeList(0, 10, 1, true); g12.AddEdgeList(10, 11, 1, true);
g12.AddEdgeList(10, 12, 1, true);
g12.AddEdgeList(10, 13, 1, true);
g12.HLD(0);
cout << g12.LCA(3, 6) << '\n';
cout << g12.LCA(9, 13) << '\n';
// bi graph match
Graph_adj g13(8);
g13.AddEdgeList(0, 3, 1, true);
g13.AddEdgeList(0, 5, 1, true);
g13.AddEdgeList(2, 1, 1, true);
g13.AddEdgeList(4, 3, 1, true);
g13.AddEdgeList(6, 3, 1, true);
g13.AddEdgeList(6, 7, 1, true);
if (g13.BFS_bi()) {
tuple<int, int, vector<list<int>>> bi_adj = g13.GetBIG();
BipGraph g14(bi_adj);
vector<pair<int, int>> match = g14.HopcroftKarp();
g13.GetMatch(match);
}
else cout << "not bi graph\n";
return 0;
}
```
### merge sort
```c++=1
#include <iostream>
using namespace std;
void merge(int arr[], int l, int r, int m) {
int lenA = m - l + 1;
int lenB = r - m;
int a[lenA] = {0};
int b[lenB] = {0};
for (int i = 0; i < lenA; i++)
a[i] = arr[l+i];
for (int i = 0; i < lenB; i++)
b[i] = arr[m+1+i];
int i = 0, j = 0, k = l;
while (i < lenA && j < lenB) {
if (a[i] < b[j]) {
arr[k] = a[i];
i++;
} else {
arr[k] = b[j];
j++;
}
k++;
}
while (i < lenA) {
arr[k] = a[i];
i++;
k++;
}
while (j < lenB) {
arr[k] = b[j];
j++;
k++;
}
}
void mergeSort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, r, m);
}
}
int main() {
int N;
cin >> N;
int a[N] = {0};
for (int i = 0; i < N; i++)
cin >> a[i];
mergeSort(a, 0, N-1);
for (int i = 0; i < N; i++)
cout << a[i] << " ";
cout << '\n';
return 0;
}
```
### heap sort
```C++=1
#include <iostream>
using namespace std;
//i = 0...N
void heapify(int arr[], int n, int i) {
int largest = i;
int l = 2*i+1;
int r = 2*i+2;
if (l < n && arr[l] > arr[largest])
largest = l;
if (r < n && arr[r] > arr[largest])
largest = r;
if (largest != i) {
swap(arr[largest], arr[i]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n) {
for (int i = n/2-1; i >= 0; i--)
heapify(arr, n, i);
for (int i = n-1; i >= 1; i--) {
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
int main() {
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++)
cin >> a[i];
heapSort(a, n);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
```
### radix sort
```c++=1
// implementation of radix sort using bin/bucket sort
#include <bits/stdc++.h>
using namespace std;
// structure for a single linked list to help further in the
// sorting
struct node {
int data;
node* next;
};
// function for creating a new node in the linked list
struct node* create(int x)
{
node* temp = new node();
temp->data = x;
temp->next = NULL;
return temp;
}
// utility function to append node in the linked list
// here head is passed by reference, to know more about this
// search pass by reference
void insert(node*& head, int n)
{
if (head == NULL) {
head = create(n);
return;
}
node* t = head;
while (t->next != NULL)
t = t->next;
t->next = create(n);
}
// utility function to pop an element from front in the list
// for the sake of stability in sorting
int del(node*& head)
{
if (head == NULL)
return 0;
node* temp = head;
// storing the value of head before updating
int val = head->data;
// updation of head to next node
head = head->next;
delete temp;
return val;
}
// utility function to get the number of digits in the
// max_element
int digits(int n)
{
int i = 1;
if (n < 10)
return 1;
while (n > (int)pow(10, i))
i++;
return i;
}
void radix_sort(vector<int>& arr)
{
// size of the array to be sorted
int sz = arr.size();
// getting the maximum element in the array
int max_val = *max_element(arr.begin(), arr.end());
// getting digits in the maximum element
int d = digits(max_val);
// creating buckets to store the pointers
node** bins;
// array of pointers to linked list of size 10 as
// integers are decimal numbers so they can hold numbers
// from 0-9 only, that's why size of 10
bins = new node*[10];
// initializing the hash array with null to all
for (int i = 0; i < 10; i++)
bins[i] = NULL;
// first loop working for a constant time only and inner
// loop is iterating through the array to store elements
// of array in the linked list by their digits value
for (int i = 0; i < d; i++) {
for (int j = 0; j < sz; j++) // bins updation
insert(bins[(arr[j] / (int)pow(10, i)) % 10],
arr[j]);
int x = 0, y = 0;
// write back to the array after each pass
while (x < 10) {
while (bins[x] != NULL)
arr[y++] = del(bins[x]);
x++;
}
}
}
// a utility function to print the sorted array
void print(vector<int> arr)
{
for (int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
}
int main()
{
vector<int> arr = { 573, 25, 415, 12, 161, 6 };
// function call
radix_sort(arr);
print(arr);
return 0;
}
```
### shell sort
```c++=1
void swap(int *a, int *b){
int temp;
temp = *a;
*a = *b;
*b= temp;
};
int shell_sort(int A[], int n){
int span, i;
span = n/2;
while(span>=1){
for(i = 0; i<(n-span); i++){
if(A[i]>A[i+span]){
swap(&A[i], &A[i+span]);
}
}
span = span/2;
}
};
int main(){
int count, i;
scanf("%d", &count);
int list[count];
printf("Numbers to be sorted: ");
for(i = 0; i<count; i++){
scanf("%d", &list[i]);
printf("%d ", list[i]);
}
printf("\n");
shell_sort(list, count);
printf("Numbers Sorted: ");
for(i = 0; i<count; i++){
printf("%d ", list[i]);
}
return 0;
}
```
### GCD
```c++=1
int gcd(int a, int b) {
while (b) {
int r = a % b;
a = b;
b = r;
}
return a;
}
```
### 終極密碼 (猜能成功的最小答案)
```c++=1
bool simulate(const int& a, const int& t) {
// success -> true
// fail -> false
return a > t;
}
int guess(vector<int> &data, int target) {
auto begin = data.begin();
auto end = data.end();
sort(data.begin(), data.end()); // increase (default)
// data.begin()+1 ~ data.end() may be ans, no data.begin()
while (end - begin > 1) {
auto mid = begin + (end - begin)/2;
// success
if (simulate(*mid, target)) end = mid;
// fail
else begin = mid;
}
if (end == data.end()) return -1;
else return *end; // min success
}
```
### 大數運算
``` C++=1
//#include<cstring>
//讀取大數
void scan(char s[100], int a[100])
{
int i = 100 - 1;
int j = 0, n = strlen(s);
while (i >= n) a[i--] = 0;
while (i >= 0) a[i--] = s[j++] - '0';
}
//印出大數
void print(int a[100])
{
int i = 100 - 1;
while (i >= 0 && a[i] == 0) i--;
if (i < 0)
cout << '0';
else
while (i >= 0) cout << a[i--];
}
//比較大小
bool largerthan(int a[100], int b[100])
{
for (int i=100-1; i>=0; i--)
if (a[i] != b[i]) 。
return a[i] > b[i];
return false;
}
//大數加法
void add(int a[100], int b[100], int c[100])
{
for (int i=0; i<100; i++)
c[i] = a[i] + b[i];
for (int i=0; i<100-1; i++)
{
c[i+1] += c[i] / 10;
c[i] %= 10;
}
}
//大數減法
void sub(int a[100], int b[100], int c[100])
{
for (int i=0; i<100; i++)
c[i] = a[i] - b[i];
for (int i=0; i<100-1; i++)
if (c[i] < 0)
{
c[i+1]--;
c[i] += 10;
}
}
//大數乘法
void mul(int a[100], int b[100], int c[100])
{
for (int i=0; i<100; i++)
c[i] = 0;
for (int i=0; i<100; i++)
for (int j=0; j<100; j++)
if (i+j < 100)
c[i+j] += a[i] * b[j];
for (int i=0; i<100-1; i++)
{
c[i+1] += c[i] / 10;
c[i] %= 10;
}
}
void mul(int a[100], int b, int c[100])
{
for (int i=0; i<100; i++)
c[i] = a[i] * b;
for (int i=0; i<100-1; i++)
{
c[i+1] += c[i] / 10;
c[i] %= 10;
}
}
//大數除法
void div(int a[100], int b[100], int c[100])
{
int t[100];
for (int i=100-1; i>=0; i--)
for (int k=9; k>0; k--)
{
mul(b+i, k, t);
if (largerthan(a+i, t))
{
sub(a+i, t, c+i);
break;
}
}
}
void div(int a[100], int b, int c[100])
{
int r = 0;
for (int i=100-1; i>=0; i--)
{
r = r * 10 + a[i];
c[i] = r / b;
r %= b;
}
}
```
### Single Source Shortest Path
#### Bellmon Ford
``` C++
// A C++ program for Bellman-Ford's single source
// shortest path algorithm.
#include <bits/stdc++.h>
// a structure to represent a weighted edge in graph
struct Edge {
int src, dest, weight;
};
// a structure to represent a connected, directed and
// weighted graph
struct Graph {
// V-> Number of vertices, E-> Number of edges
int V, E;
// graph is represented as an array of edges.
struct Edge* edge;
};
// Creates a graph with V vertices and E edges
struct Graph* createGraph(int V, int E)
{
struct Graph* graph = new Graph;
graph->V = V;
graph->E = E;
graph->edge = new Edge[E];
return graph;
}
// A utility function used to print the solution
void printArr(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < n; ++i)
printf("%d \t\t %d\n", i, dist[i]);
}
// The main function that finds shortest distances from src to
// all other vertices using Bellman-Ford algorithm. The function
// also detects negative weight cycle
void BellmanFord(struct Graph* graph, int src)
{
int V = graph->V;
int E = graph->E;
int dist[V];
// Step 1: Initialize distances from src to all other vertices
// as INFINITE
for (int i = 0; i < V; i++)
dist[i] = INT_MAX;
dist[src] = 0;
// Step 2: Relax all edges |V| - 1 times. A simple shortest
// path from src to any other vertex can have at-most |V| - 1
// edges
for (int i = 1; i <= V - 1; i++) {
for (int j = 0; j < E; j++) {
int u = graph->edge[j].src;
int v = graph->edge[j].dest;
int weight = graph->edge[j].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v])
dist[v] = dist[u] + weight;
}
}
// Step 3: check for negative-weight cycles. The above step
// guarantees shortest distances if graph doesn't contain
// negative weight cycle. If we get a shorter path, then there
// is a cycle.
for (int i = 0; i < E; i++) {
int u = graph->edge[i].src;
int v = graph->edge[i].dest;
int weight = graph->edge[i].weight;
if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) {
printf("Graph contains negative weight cycle");
return; // If negative cycle is detected, simply return
}
}
printArr(dist, V);
return;
}
// Driver program to test above functions
int main()
{
/* Let us create the graph given in above example */
int V = 5; // Number of vertices in graph
int E = 8; // Number of edges in graph
struct Graph* graph = createGraph(V, E);
// add edge 0-1 (or A-B in above figure)
graph->edge[0].src = 0;
graph->edge[0].dest = 1;
graph->edge[0].weight = -1;
// add edge 0-2 (or A-C in above figure)
graph->edge[1].src = 0;
graph->edge[1].dest = 2;
graph->edge[1].weight = 4;
// add edge 1-2 (or B-C in above figure)
graph->edge[2].src = 1;
graph->edge[2].dest = 2;
graph->edge[2].weight = 3;
// add edge 1-3 (or B-D in above figure)
graph->edge[3].src = 1;
graph->edge[3].dest = 3;
graph->edge[3].weight = 2;
// add edge 1-4 (or A-E in above figure)
graph->edge[4].src = 1;
graph->edge[4].dest = 4;
graph->edge[4].weight = 2;
// add edge 3-2 (or D-C in above figure)
graph->edge[5].src = 3;
graph->edge[5].dest = 2;
graph->edge[5].weight = 5;
// add edge 3-1 (or D-B in above figure)
graph->edge[6].src = 3;
graph->edge[6].dest = 1;
graph->edge[6].weight = 1;
// add edge 4-3 (or E-D in above figure)
graph->edge[7].src = 4;
graph->edge[7].dest = 3;
graph->edge[7].weight = -3;
BellmanFord(graph, 0);
return 0;
}
```
#### Dijskstra's
```C++
// A C++ program for Dijkstra's single source shortest path algorithm.
// The program is for adjacency matrix representation of the graph
#include <limits.h>
#include <stdio.h>
// Number of vertices in the graph
#define V 9
// A utility function to find the vertex with minimum distance value, from
// the set of vertices not yet included in shortest path tree
int minDistance(int dist[], bool sptSet[])
{
// Initialize min value
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++)
if (sptSet[v] == false && dist[v] <= min)
min = dist[v], min_index = v;
return min_index;
}
// A utility function to print the constructed distance array
int printSolution(int dist[], int n)
{
printf("Vertex Distance from Source\n");
for (int i = 0; i < V; i++)
printf("%d \t\t %d\n", i, dist[i]);
}
// Function that implements Dijkstra's single source shortest path algorithm
// for a graph represented using adjacency matrix representation
void dijkstra(int graph[V][V], int src)
{
int dist[V]; // The output array. dist[i] will hold the shortest
// distance from src to i
bool sptSet[V]; // sptSet[i] will be true if vertex i is included in shortest
// path tree or shortest distance from src to i is finalized
// Initialize all distances as INFINITE and stpSet[] as false
for (int i = 0; i < V; i++)
dist[i] = INT_MAX, sptSet[i] = false;
// Distance of source vertex from itself is always 0
dist[src] = 0;
// Find shortest path for all vertices
for (int count = 0; count < V - 1; count++) {
// Pick the minimum distance vertex from the set of vertices not
// yet processed. u is always equal to src in the first iteration.
int u = minDistance(dist, sptSet);
// Mark the picked vertex as processed
sptSet[u] = true;
// Update dist value of the adjacent vertices of the picked vertex.
for (int v = 0; v < V; v++)
// Update dist[v] only if is not in sptSet, there is an edge from
// u to v, and total weight of path from src to v through u is
// smaller than current value of dist[v]
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
// print the constructed distance array
printSolution(dist, V);
}
// driver program to test above function
int main()
{
/* Let us create the example graph discussed above */
int graph[V][V] = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 },
{ 4, 0, 8, 0, 0, 0, 0, 11, 0 },
{ 0, 8, 0, 7, 0, 4, 0, 0, 2 },
{ 0, 0, 7, 0, 9, 14, 0, 0, 0 },
{ 0, 0, 0, 9, 0, 10, 0, 0, 0 },
{ 0, 0, 4, 14, 10, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 1, 6 },
{ 8, 11, 0, 0, 0, 0, 1, 0, 7 },
{ 0, 0, 2, 0, 0, 0, 6, 7, 0 } };
dijkstra(graph, 0);
return 0;
}
```
### All Path Shortest Path
#### Floyd-Washall
``` C++
// C++ Program for Floyd Warshall Algorithm
#include <bits/stdc++.h>
using namespace std;
// Number of vertices in the graph
#define V 4
/* Define Infinite as a large enough
value.This value will be used for
vertices not connected to each other */
#define INF 99999
// A function to print the solution matrix
void printSolution(int dist[][V]);
// Solves the all-pairs shortest path
// problem using Floyd Warshall algorithm
void floydWarshall(int graph[][V])
{
/* dist[][] will be the output matrix
that will finally have the shortest
distances between every pair of vertices */
int dist[V][V], i, j, k;
/* Initialize the solution matrix same
as input graph matrix. Or we can say
the initial values of shortest distances
are based on shortest paths considering
no intermediate vertex. */
for (i = 0; i < V; i++)
for (j = 0; j < V; j++)
dist[i][j] = graph[i][j];
/* Add all vertices one by one to
the set of intermediate vertices.
---> Before start of an iteration,
we have shortest distances between all
pairs of vertices such that the
shortest distances consider only the
vertices in set {0, 1, 2, .. k-1} as
intermediate vertices.
----> After the end of an iteration,
vertex no. k is added to the set of
intermediate vertices and the set becomes {0, 1, 2, ..
k} */
for (k = 0; k < V; k++) {
// Pick all vertices as source one by one
for (i = 0; i < V; i++) {
// Pick all vertices as destination for the
// above picked source
for (j = 0; j < V; j++) {
// If vertex k is on the shortest path from
// i to j, then update the value of
// dist[i][j]
if (dist[i][j] > (dist[i][k] + dist[k][j])
&& (dist[k][j] != INF
&& dist[i][k] != INF))
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// Print the shortest distance matrix
printSolution(dist);
}
/* A utility function to print solution */
void printSolution(int dist[][V])
{
cout << "The following matrix shows the shortest "
"distances"
" between every pair of vertices \n";
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][j] == INF)
cout << "INF"
<< " ";
else
cout << dist[i][j] << " ";
}
cout << endl;
}
}
// Driver code
int main()
{
/* Let us create the following weighted graph
10
(0)------->(3)
| /|\
5 | |
| | 1
\|/ |
(1)------->(2)
3 */
int graph[V][V] = { { 0, 5, INF, 10 },
{ INF, 0, 3, INF },
{ INF, INF, 0, 1 },
{ INF, INF, INF, 0 } };
// Print the solution
floydWarshall(graph);
return 0;
}
// This code is contributed by Mythri J L
```
### hungarian algorithm
``` C++
#include<vector>
#include<queue>
#include<limits>
#include<iostream>
using namespace std;
// Hungarian Algorithm - O(V^3)
class WeightedBipartiteMatching {
int n;
vector<long long> lx{}, ly{};
vector<bool> vx{}, vy{};
queue<int> qu{}; // only X's vertices
vector<int> py{};
vector<long long> dy{}; // smallest (lx[x] + ly[y] - w[x][y])
vector<int> pdy{}; // & which x
vector<int> mx{}, my{};
void relax(const vector<vector<long long>>& w, int x) {
for (int y{0}; y < n; ++y)
if (lx[x] + ly[y] - w[x][y] < dy[y])
dy[y] = lx[x] + ly[y] - w[x][y], pdy[y] = x;
}
void augment(int y) {
while (y != -1) {
int x{py[y]}, yy{mx[x]};
mx[x] = y, my[y] = x;
y = yy;
}
}
bool bfs(const vector<vector<long long>>& w) {
while (!qu.empty()) {
int x{qu.front()}; qu.pop();
for (int y{0}; y < n; ++y) {
if (!vy[y] && lx[x] + ly[y] == w[x][y]) {
vy[y] = true, py[y] = x;
if (my[y] == -1) return augment(y), true;
int xx{my[y]};
qu.push(x), vx[xx] = true, relax(w, xx);
}
}
}
return false;
}
void relabel() {
long long d{numeric_limits<long long>::max()};
for (int y{0}; y < n; ++y) if (!vy[y]) d = min(d, dy[y]);
for (int x{0}; x < n; ++x) if (vx[x]) lx[x] -= d;
for (int y{0}; y < n; ++y) if (vy[y]) ly[y] += d;
for (int y{0}; y < n; ++y) if (!vy[y]) dy[y] -= d;
}
bool expand(const vector<vector<long long>>& w) { // expand one layer with new equality edges
for (int y{0}; y < n; ++y) {
if (!vy[y] && dy[y] == 0) {
vy[y] = true, py[y] = pdy[y];
if (my[y] == -1) return augment(y), true;
int xx{my[y]};
qu.push(xx), vx[xx] = true, relax(w, xx);
}
}
return false;
}
public:
pair<vector<int>, vector<int>> operator()(const vector<vector<long long>>& w) {
n = w.size(), lx.assign(n, 0), ly.assign(n, 0), vx.resize(n), vy.resize(n), py.resize(n), dy.resize(n), pdy.resize(n), mx.assign(n, -1), my.assign(n, -1);
for (int i{0}; i < n; ++i)
for (int j{0}; j < n; ++j)
lx[i] = max(lx[i], w[i][j]);
for (int x{0}; x < n; ++x) {
fill(vx.begin(), vx.end(), false);
fill(vy.begin(), vy.end(), false);
fill(dy.begin(), dy.end(), numeric_limits<long long>::max());
qu = {}, qu.push(x), vx[x] = true, relax(w, x);
while (!bfs(w)) {
relabel();
if (expand(w)) break;
}
}
return {move(mx), move(my)}; // mx 矩陣由上往下看選到的index my 矩陣由左往右看選到的index
}
};
int main(){
vector<vector<long long>> MM{{-2500,-4000,-3500}, {-4000,-6000,-3500}, {-2000,-4000,-2500}}; // 正數 -> 選最大匹配 , 變負數 ->改成選最小匹配
pair<vector<int>,vector<int>> result;
class WeightedBipartiteMatching A;
int i,j;
for(i=0;i<3;i++){
for(j=0;j<3;j++){
cout << MM[i][j] <<' ';
}
cout << '\n';
}
result=A(MM);
for(i=0;i<3;i++){
cout << (result.first)[i]<<' ';
}
cout << '\n';
for(i=0;i<3;i++){
cout << (result.second)[i]<<' ';
}
return 0;
}
```
### 最大流量/最小切割
```C++
// C++ program for implementation of Ford Fulkerson algorithm
#include <iostream>
#include <limits.h>
#include <string.h>
#include <queue>
using namespace std;
// Number of vertices in given graph
#define V 6
/* Returns true if there is a path from source 's' to sink 't' in
residual graph. Also fills parent[] to store the path */
bool bfs(int rGraph[V][V], int s, int t, int parent[])
{
// Create a visited array and mark all vertices as not visited
bool visited[V];
memset(visited, 0, sizeof(visited));
// Create a queue, enqueue source vertex and mark source vertex as visited
queue<int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
// Standard BFS Loop
int u;
while (!q.empty())
{
// edge: u -> v
u = q.front(); // head point u
q.pop();
for (int v = 0; v < V; ++v) // tail point v
{
if (!visited[v] && rGraph[u][v] > 0) // find one linked vertex
{
q.push(v);
parent[v] = u; // find pre point
visited[v] = true;
}
}
}
// If we reached sink in BFS starting from source, then return true, else false
return visited[t] == true;
}
// Returns the maximum flow from s to t in the given graph
int fordFulkerson(int graph[V][V], int s, int t)
{
int u, v;
int rGraph[V][V];
for (u = 0; u < V; ++u)
{
for (v = 0; v < V; ++v)
{
rGraph[u][v] = graph[u][v];
}
}
int parent[V];
int max_flow = 0;
// Augment the flow while tere is path from source to sink
while (bfs(rGraph, s, t, parent))
{
// edge: u -> v
int path_flow = INT_MAX;
for (v = t; v != s; v = parent[v])
{
// find the minimum flow
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
// update residual capacities of the edges and reverse edges along the path
for (v = t; v != s; v = parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow; // assuming v->u weight is add path_flow
}
// Add path flow to overall flow
max_flow += path_flow;
}
return max_flow;
}
int main()
{
int graph[V][V] = { {0,16,13, 0, 0, 0},
{0, 0,10,12, 0, 0},
{0, 4, 0, 0,14, 0},
{0, 0, 9, 0, 0,20},
{0, 0, 0, 7, 0, 4},
{0, 0, 0, 0, 0, 0}
};
cout << fordFulkerson(graph, 0, 5);
return 0;
}
```
### 🌸
``` C++
/*
GETS:
V->number of vertices
E->number of edges
pair of vertices as edges (vertices are 1..V)
GIVES:
output of edmonds() is the maximum matching
match[i] is matched pair of i (-1 if there isn't a matched pair)
*/
#include <bits/stdc++.h>
using namespace std;
const int M=500;
struct struct_edge{int v;struct_edge* n;};
typedef struct_edge* edge;
struct_edge pool[M*M*2];
edge top=pool,adj[M];
int V,E,match[M],qh,qt,q[M],father[M],base[M];
bool inq[M],inb[M],ed[M][M];
void add_edge(int u,int v)
{
top->v=v,top->n=adj[u],adj[u]=top++;
top->v=u,top->n=adj[v],adj[v]=top++;
}
int LCA(int root,int u,int v)
{
static bool inp[M];
memset(inp,0,sizeof(inp));
while(1)
{
inp[u=base[u]]=true;
if (u==root) break;
u=father[match[u]];
}
while(1)
{
if (inp[v=base[v]]) return v;
else v=father[match[v]];
}
}
void mark_blossom(int lca,int u)
{
while (base[u]!=lca)
{
int v=match[u];
inb[base[u]]=inb[base[v]]=true;
u=father[v];
if (base[u]!=lca) father[u]=v;
}
}
void blossom_contraction(int s,int u,int v)
{
int lca=LCA(s,u,v);
memset(inb,0,sizeof(inb));
mark_blossom(lca,u);
mark_blossom(lca,v);
if (base[u]!=lca)
father[u]=v;
if (base[v]!=lca)
father[v]=u;
for (int u=0;u<V;u++)
if (inb[base[u]])
{
base[u]=lca;
if (!inq[u])
inq[q[++qt]=u]=true;
}
}
int find_augmenting_path(int s)
{
memset(inq,0,sizeof(inq));
memset(father,-1,sizeof(father));
for (int i=0;i<V;i++) base[i]=i;
inq[q[qh=qt=0]=s]=true;
while (qh<=qt)
{
int u=q[qh++];
for (edge e=adj[u];e;e=e->n)
{
int v=e->v;
if (base[u]!=base[v]&&match[u]!=v)
if ((v==s)||(match[v]!=-1 && father[match[v]]!=-1))
blossom_contraction(s,u,v);
else if (father[v]==-1)
{
father[v]=u;
if (match[v]==-1)
return v;
else if (!inq[match[v]])
inq[q[++qt]=match[v]]=true;
}
}
}
return -1;
}
int augment_path(int s,int t)
{
int u=t,v,w;
while (u!=-1)
{
v=father[u];
w=match[v];
match[v]=u;
match[u]=v;
u=w;
}
return t!=-1;
}
int edmonds()
{
int matchc=0;
memset(match,-1,sizeof(match));
for (int u=0;u<V;u++)
if (match[u]==-1)
matchc+=augment_path(u,find_augmenting_path(u));
return matchc;
}
int main()
{
int u, v;
cin >> V >> E;
while(E--)
{
cin >> u >> v;
if (!ed[u-1][v-1])
{
add_edge(u-1,v-1);
ed[u-1][v-1] = ed[v-1][u-1] = true;
}
}
cout << edmonds() << endl;
for (int i = 0; i < V; i++)
if (i < match[i])
cout << i+1 << " " << match[i]+1 << endl;
}
```
🚰
``` C++
#include <iostream>
#include <vector>
#include <queue>
#include <cstdio>
#include <cstring>
#define MAXN 100
#define INF 2147483647
#define ull unsigned long long
using namespace std;
struct MaxFlow{
struct edge{
int to, cap, flow;
ull rev;
};
vector<edge> v[MAXN];
int s, t, dis[MAXN], cur[MAXN];
int dfs(int u, int cap){
if(u == t || !cap)
return cap;
for(int &i = cur[u]; i < v[u].size(); i++){
edge &e = v[u][i];
if(dis[e.to] == dis[u] + 1 && e.flow != e.cap){
int df = dfs(e.to, min(e.cap - e.flow, cap));
if(df){
e.flow += df;
v[e.to][e.rev].flow -= df;
return df;
}
}
}
dis[u] = -1;
return 0;
}
bool bfs(){
memset(dis, -1, sizeof(dis));
queue<int> q;
q.push(s), dis[s] = 0;
while(!q.empty()){
int tmp = q.front();
q.pop();
for(auto &u : v[tmp]){
if(!~dis[u.to] && u.flow != u.cap){
q.push(u.to);
dis[u.to] = dis[tmp] + 1;
}
}
}
return dis[t] != -1;
}
int maxflow(int _s, int _t){
s = _s, t = _t;
int flow = 0, df;
while(bfs()){
memset(cur, 0, sizeof(cur));
while(df = dfs(s, INF)){
flow += df;
}
}
return flow;
}
void addedge(int st, int ed, int cap){
v[st].push_back(edge{ed, cap, 0, v[ed].size()});
v[ed].push_back(edge{st, 0, 0, v[st].size() - 1});
}
};
int main() {
MaxFlow maxflow;
maxflow.addedge(0, 1, 3);
maxflow.addedge(0, 2, 1);
maxflow.addedge(1, 2, 2);
maxflow.addedge(1, 3, 2);
maxflow.addedge(2, 3, 2);
cout << maxflow.maxflow(0, 3) << endl;
cout << "------" << endl;
MaxFlow maxflow2;
int n, e;
cin >> n >> e;
int s, t;
cin >> s >> t;
int u, v, cap;
for (int i = 0; i < e; i++) {
cin >> u >> v >> cap;
maxflow2.addedge(u, v, cap);
}
cout << maxflow2.maxflow(s, t) << endl;
}
```