Skip to content

Commit

Permalink
Merge pull request #97 from rainbou-kpr/graph_util
Browse files Browse the repository at this point in the history
add graph_util
  • Loading branch information
KowerKoint authored Jan 17, 2024
2 parents 8934da0 + ae253f1 commit d6ff9e2
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .verify-helper/timestamps.remote.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
"test/aoj-grl-5-b.test.cpp": "2023-06-16 15:41:49 +0900",
"test/atcoder-abc177-f.1.test.cpp": "2023-08-01 17:59:54 +0900",
"test/atcoder-abc177-f.2.test.cpp": "2023-08-01 17:59:54 +0900",
"test/atcoder-abc282-d.test.cpp": "2023-11-30 23:29:28 +0900",
"test/atcoder-abc300-b.test.cpp": "2023-10-12 08:50:40 +0900",
"test/atcoder-edpc-g.test.cpp": "2023-06-06 14:52:29 +0900",
"test/atcoder-edpc-g.test.cpp": "2023-11-30 23:29:28 +0900",
"test/atcoder-past202012-n.test.cpp": "2023-08-01 18:34:30 +0900",
"test/atcoder-past202012-n.test.py": "2023-09-07 14:26:13 +0900",
"test/yosupo-binomial-coefficient.test.cpp": "2023-09-16 00:25:06 +0900",
Expand Down
119 changes: 119 additions & 0 deletions cpp/graph_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#pragma once

/**
* @file graph_util.hpp
* @brief グラフに関する関数
*/

#include <stack>

#include "graph.hpp"

/**
* @brief 無向グラフについて、二部グラフなら0と1に彩色した結果をひとつ返し、二部グラフでないなら空のvectorを返す。
* 連結成分のうち、インデックスの最も小さいものを0にする。
* @return std::vector<int> 各頂点の彩色結果
*/
template <typename Cost = int>
std::vector<int> bipartite_coloring(const Graph<Cost>& graph) {
std::vector<int> color(graph.n, -1);
for (int i = 0; i < graph.n; i++) {
if (color[i] != -1) continue;
std::stack<int> stk;
stk.push(i);
color[i] = 0;
while (!stk.empty()) {
int u = stk.top();
stk.pop();
for (int v : graph[u]) {
if (color[v] == -1) {
color[v] = color[u] ^ 1;
stk.push(v);
} else {
if (color[u] == color[v]) return {};
}
}
}
}
return color;
}

/**
* @brief 無向グラフについて、二部グラフかどうかを判定する。
* @return bool 二部グラフならtrue、二部グラフでないならfalseを返す。
*/
template <typename Cost = int>
bool is_bipartite(const Graph<Cost>& graph) {
return !bipartite_coloring(graph).empty();
}

/**
* @brief 無向グラフについて、連結成分分解する。
* @return std::vector<std::vector<int>> 「同じ連結成分となる頂点のリスト」のリスト
*/
template <typename Cost = int>
std::vector<std::vector<int>> connected_components(const Graph<Cost>& graph) {
std::vector<std::vector<int>> groups;
std::vector<bool> visited(graph.n);
for (int i = 0; i < graph.n; i++) {
if (visited[i]) continue;
std::stack<int> stk;
stk.push(i);
visited[i] = true;
groups.push_back({i});
while (!stk.empty()) {
int u = stk.top();
stk.pop();
for (int v : graph[u]) {
if (visited[v]) continue;
visited[v] = true;
stk.push(v);
groups.back().push_back(v);
}
}
}
return groups;
}

/**
* @brief 無向グラフについて、連結グラフかどうかを判定する。
* @return bool 連結グラフならtrue、連結グラフでないならfalseを返す。
*/
template <typename Cost = int>
bool is_connected(const Graph<Cost>& graph) {
return connected_components(graph).size() == 1;
}

/**
* @brief 無向グラフについて、木かどうかを判定する。
* @return bool 木ならtrue、木でないならfalseを返す。
*/
template <typename Cost = int>
bool is_tree(const Graph<Cost>& graph) {
return graph.m == graph.n - 1 && is_connected(graph);
}

/**
* @brief 有向グラフをトポロジカルソートする
* @param G トポロジカルソートするグラフ
* @return ソートされたノード番号のvector DAGでなければ長さがG.n未満になる
*/
template<typename Cost>
std::vector<int> topological_sort(const Graph<Cost> &G) {
std::vector<int> indeg(G.n), sorted;
std::queue<int> q;
for (int i = 0; i < G.n; i++) {
for (int dst : G[i]) indeg[dst]++;
}
for (int i = 0; i < G.n; i++) {
if (!indeg[i]) q.push(i);
}
while (!q.empty()) {
int cur = q.front(); q.pop();
for (int dst : G[cur]) {
if (!--indeg[dst]) q.push(dst);
}
sorted.push_back(cur);
}
return sorted;
}
27 changes: 27 additions & 0 deletions test/atcoder-abc282-d.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#define PROBLEM "https://atcoder.jp/contests/abc282/tasks/abc282_d"

#include <algorithm>
#include <array>

#include "../cpp/graph_util.hpp"

int main(void) {
int N, M;
std::cin >> N >> M;
Graph<int> graph(N);
graph.read(M);
std::vector<int> c = bipartite_coloring(graph);
if (c.empty()) {
std::cout << 0 << std::endl;
return 0;
}
std::vector<std::vector<int>> groups = connected_components(graph);
long long ans = (long long)N * (N - 1) / 2 - M;
for (const std::vector<int>& group : groups) {
std::array<long long, 2> wb = {};
std::for_each(group.begin(), group.end(), [&](int x) { wb[c[x]]++; });
auto [w, b] = wb;
ans -= w * (w - 1) / 2 + b * (b - 1) / 2;
}
std::cout << ans << std::endl;
}
6 changes: 3 additions & 3 deletions test/atcoder-edpc-g.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <iostream>
#include <algorithm>

#include "../cpp/graph.hpp"
#include "../cpp/graph_util.hpp"

int main(void){

Expand All @@ -12,8 +12,8 @@ int main(void){
Graph G(N);
G.read(M, -1, false, true);

std::vector<int> dist(N);
for(int x : G.topological_sort()){
std::vector<int> dist(N), ord(topological_sort(G));
for(int x : ord){
for(int y : G[x]) dist[y] = std::max(dist[y], dist[x] + 1);
}
std::cout << *std::max_element(dist.begin(), dist.end()) << std::endl;
Expand Down

0 comments on commit d6ff9e2

Please sign in to comment.