Skip to content

Instantly share code, notes, and snippets.

@kamino410
Last active April 5, 2020 16:19
Show Gist options
  • Select an option

  • Save kamino410/bc16922112a85b9dcb728c895b6e9aec to your computer and use it in GitHub Desktop.

Select an option

Save kamino410/bc16922112a85b9dcb728c895b6e9aec to your computer and use it in GitHub Desktop.

combination

import math

def combinations_count(n, r):
    return math.factorial(n) // (math.factorial(n - r) * math.factorial(r))
#include <functional>

#include <iostream>

void recursive_comb(int *indexes, int s, int rest, std::function<void(int *)> f) {
  if (rest == 0) {
    f(indexes);
  } else {
    if (s < 0) return;
    recursive_comb(indexes, s - 1, rest, f);
    indexes[rest - 1] = s;
    recursive_comb(indexes, s - 1, rest - 1, f);
  }
}

// nCkの組み合わせに対して処理を実行する
void foreach_comb(int n, int k, std::function<void(int *)> f) {
  int indexes[k];
  recursive_comb(indexes, n - 1, k, f);
}

int main() {
  foreach_comb(5, 3, [](int *indexes) {
    std::cout << indexes[0] << ',' << indexes[1] << ',' << indexes[2] << std::endl;
  });
}
#include <functional>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

// 0~k-1のすべての組み合わせに対して処理を行う
void combination(int k, std::function<void(std::vector<int>)> f) {
  for (int i = 0; i < (1 << k); i++) {
    std::vector<int> nums;
    for (int j = 0; j < k; j++) {
      if ((1 << j) & i) nums.push_back(j);
    }
    f(nums);
  }
}

int main() {
  combination(2, [](std::vector<int> nums) {
    for (int i = 0; i < nums.size(); i++) cout << nums[i] << " ";
    cout << endl;
  });
}

permutation

import math

def permutations_count(n, r):
    return math.factorial(n) // math.factorial(n - r)
#include <algorithm>
#include <functional>

#include <iostream>

void recursive_comb(int *indexes, int s, int rest, std::function<void(int *)> f) {
  if (rest == 0) {
    f(indexes);
  } else {
    if (s < 0) return;
    recursive_comb(indexes, s - 1, rest, f);
    indexes[rest - 1] = s;
    recursive_comb(indexes, s - 1, rest - 1, f);
  }
}

// nCkの組み合わせに対して処理を実行する
void foreach_comb(int n, int k, std::function<void(int *)> f) {
  int indexes[k];
  recursive_comb(indexes, n - 1, k, f);
}

// nPnの順列に対して処理を実行する
void foreach_permutation(int n, std::function<void(int *)> f) {
  int indexes[n];
  for (int i = 0; i < n; i++) indexes[i] = i;
  do {
    f(indexes);
  } while (std::next_permutation(indexes, indexes + n));
}

// nPkの順列に対して処理を実行する
void foreach_permutation(int n, int k, std::function<void(int *)> f) {
  foreach_comb(n, k, [&](int *c_indexes) {
    foreach_permutation(k, [&](int *p_indexes) {
      int indexes[k];
      for (int i = 0; i < k; i++) {
        indexes[i] = c_indexes[p_indexes[i]];
      }
      f(indexes);
    });
  });
}

int main() {
  foreach_permutation(
      4, 2, [](int *indexes) { std::cout << indexes[0] << ',' << indexes[1] << std::endl; });
}

sort

#include <algorithm>
#include <iostream>

int main() {
  int nums[] = {9, 3, 4, 2, 6, 1, 7, 8, 5};

  // 昇順
  std::sort(nums, nums + 9);
  // 降順
  std::sort(nums, nums + 9, [](const int &a, const int &b) -> bool { return a > b; });

  for (auto n : nums) { std::cout << n << ", "; }
  std::cout << std::endl;
  return 0;
}

Union Find Tree

#include <functional>
#include <iostream>
#include <vector>

class UFTree {
private:
  const int N;           // 要素数
  std::vector<int> par;  // 各ノードの親のID(根ノードは自分を参照)
  std::vector<int> sizes;  // 各ノードを根とする木のサイズ(根でないノードには無関係)

public:
  UFTree(int n) : par(n), sizes(n, 1), N(n) {
    for (int i = 0; i < n; i++) par[i] = i;
  }

  // 要素xが属するグループの根ノードのIDを見つける
  int find(int x) {
    if (par[x] == x)
      return x;
    else
      return par[x] = find(par[x]);
  }

  // 要素x, yが属するグループ同士を統合する
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return;

    if (sizes[x] < sizes[y]) {
      par[x] = y;
      sizes[y] += sizes[x];
    } else {
      par[y] = x;
      sizes[x] += sizes[y];
    }
  }

  // グループのリストを表示する
  // (IDが小さい順に表示される, O(n^2)なので最速の実装ではない)
  void show() {
    std::cout << "Groups : " << std::endl;
    std::function<void(int)> f = [&](int x) {
      std::cout << x << ',';
      for (int y = 0; y < N; y++) {
        if (par[y] == x && y != x) f(y);
      }
    };
    for (int i = 0; i < N; i++) {
      if (par[i] == i) {
        f(i);
        std::cout << std::endl;
      }
    }
  }

  // 要素x, yが同じグループに属するかどうか
  bool same(int x, int y) { return find(x) == find(y); }

  // 要素xが所属するグループに含まれる要素の数
  int size(int x) { return sizes[find(x)]; }
};

int main() {
  UFTree uf(5);  // 0~4の5つの要素について

  uf.unite(0, 2);  // 0と2は同じグループ
  uf.unite(2, 4);  // 2と4は同じグループ
  uf.unite(1, 3);  // 1と3は同じグループ

  // 1と2は同じグループ?
  std::cout << "same(1, 2) : " << (uf.same(1, 2) ? "True" : "False") << std::endl;
  // 3が所属するグループのメンバーの数は?
  std::cout << "size(3) : " << uf.size(3) << std::endl;
  // グループのリストを表示
  uf.show();

  return 0;
}

トポロジカルソート

O(V+E)の実装。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <stack>
#include <vector>

int main() {
  const int N = 7;

  std::stringstream input;
  input << "9\n"
           "0 2\n"
           "0 3\n"
           "2 1\n"
           "3 1\n"
           "3 2\n"
           "3 4\n"
           "3 6\n"
           "4 5\n"
           "5 6";

  int graph[N][N];
  int indegrees[N];
  std::vector<int> s2t[N];
  for (int i = 0; i < N; i++) {
    indegrees[i] = 0;
    for (int j = 0; j < N; j++) { graph[i][j] = 0; }
  }

  int m;
  input >> m;
  for (int i = 0; i < m; i++) {
    int s, t;
    input >> s >> t;
    graph[s][t] = 1;
    s2t[s].push_back(t);
    indegrees[t]++;
  }

  std::vector<int> topolo_order;
  std::stack<int> st;
  for (int i = 0; i < N; i++)
    if (indegrees[i] == 0) st.push(i);

  while (st.size() > 0) {
    int i = st.top();
    st.pop();
    topolo_order.push_back(i);
    while (s2t[i].size() > 0) {
      int j = s2t[i].back();
      s2t[i].pop_back();
      indegrees[j]--;
      if (indegrees[j] == 0) st.push(j);
    }
  }

  if (topolo_order.size() != N) {
    std::cout << "The graph is not DAG" << std::endl;
  } else {
    for (int i = 0; i < N; i++) { std::cout << topolo_order[i] << ", "; }
    std::cout << std::endl;
  }
}

2次元部分和

#include <functional>
#include <iostream>
#include <string>

using namespace std;

int main() {
  const int H = 3, W = 3;
  long map[H][W] = {{0, 1, 0}, {1, 1, 0}, {1, 0, 0}};

  long table[H + 1][W + 1];
  for (int i = 0; i < H + 1; i++) { table[i][0] = 0; }
  for (int i = 0; i < W + 1; i++) { table[0][i] = 0; }

  for (int i = 0; i < H; i++) {
    long rsum = 0;
    for (int j = 0; j < W; j++) {
      rsum += map[i][j];
      table[i + 1][j + 1] = rsum + table[i][j + 1];
    }
  }

  // (y1+1,x1+1)~(y2,x2)の範囲の和
  const function<long(int, int, int, int)> partsum = [&](int y1, int x1, int y2, int x2) -> long {
    return table[y2][x2] + table[y1][x1] - table[y1][x2] - table[y2][x1];
  };

  cout << partsum(3, 3, 0, 0) << endl;
  cout << partsum(2, 2, 1, 1) << endl;
}

upper_bound_f

f(x)の呼び出し回数をlog nに抑えたupper_bound。

#include <algorithm>
#include <iostream>

using namespace std;

// 整数xに対して単調増加の関数f(x)について、k>=f(x)を満たす最大のxを求める
bool upper_bound_f(long k, long &x, long l_x, long r_x, function<long(long)> f) {
  long l_val = f(l_x);
  long r_val = f(r_x);
  if (l_val >= k || r_val < k) return false;
  while (r_x - l_x > 1) {
    x = (l_x + r_x) / 2;
    long val = f(x);
    if (val <= k) {
      l_x = x;
      l_val = val;
    } else {
      r_x = x;
      r_val = val;
    }
  }
  return true;
}

int main() {
  long data[] = {1, 2, 3, 4, 4, 6, 9, 10};
  long x;
  upper_bound_f(3, x, 0, 7, [&](long i) -> long { return data[i]; });
  cout << x << " " << data[x] << endl;
}

lower_bound_f

同じくlower_bound。

// 整数xに対して単調増加の関数f(x)について、k<=f(x)を満たす最小のxを求める
bool lower_bound_f(long k, long &x, long l_x, long r_x, function<long(long)> f) {
  long l_val = f(l_x);
  long r_val = f(r_x);
  if (l_val >= k || r_val < k) return false;
  while (r_x - l_x > 1) {
    x = (l_x + r_x + 1) / 2;
    long val = f(x);
    if (val >= k) {
      r_x = x;
      r_val = val;
    } else {
      l_x = x;
      l_val = val;
    }
  }
  return true;
}

lower_bound_f(real number)

log2(range/eps)の実装

// 実数xに対して単調増加の関数f(x)について、k<=f(x)を満たす最小のxをeps以下の精度で求める
bool lower_bound_f(double k, double &x, double l_x, double r_x, double eps,
                   function<double(double)> f) {
  long l_val = f(l_x);
  long r_val = f(r_x);
  if (l_val >= k || r_val < k) return false;
  while (abs(r_x - l_x) > eps) {
    x = (l_x + r_x) / 2;
    long val = f(x);
    if (val >= k) {
      r_x = x;
      r_val = val;
    } else {
      l_x = x;
      l_val = val;
    }
  }
  return true;
}

Geometry

const double PI = 3.14159265358979323;

struct Point {
  double x, y;
  Point(double x_ = 0, double y_ = 0) : x(x_), y(y_) {}
  Point(const Point &p) : x(p.x), y(p.y) {}
  friend std::ostream &operator<<(std::ostream &s, const Point &p) {
    return s << '(' << p.x << ", " << p.y << ')';
  }
};
inline Point operator+(const Point &p, const Point &q) { return Point(p.x + q.x, p.y + q.y); }
inline Point operator-(const Point &p, const Point &q) { return Point(p.x - q.x, p.y - q.y); }
inline Point operator*(const Point &p, double a) { return Point(p.x * a, p.y * a); }
inline Point operator*(double a, const Point &p) { return Point(a * p.x, a * p.y); }
inline Point operator/(const Point &p, double a) { return Point(p.x / a, p.y / a); }
inline Point rot(const Point &p, double ang) {
  return Point(cos(ang) * p.x - sin(ang) * p.y, sin(ang) * p.x + cos(ang) * p.y);
}
inline double dot(const Point &p, const Point &q) { return p.x * q.x + p.y * q.y; }
inline double norm(const Point &p) { return sqrt(dot(p, p)); }
inline double norm_sqrd(const Point &p) { return dot(p, p); }

struct Circle : Point {
  double r;
  Circle(const Point &p_, double r_ = 0) : Point(p_), r(r_) {}
  friend ostream &operator<<(ostream &s, const Circle &c) {
    return s << '(' << c.x << ", " << c.y << ", " << c.r << ')';
  }
};

std::vector<Point> crosspoint(const Circle &e, const Circle &f, const double eps) {
  std::vector<Point> res;
  double d = norm(e - f);
  if (d < eps) return vector<Point>();
  if (d > e.r + f.r + eps) return vector<Point>();
  if (d < abs(e.r - f.r) - eps) return vector<Point>();
  double rcos = (d * d + e.r * e.r - f.r * f.r) / (2.0 * d), rsin;
  if (e.r - abs(rcos) < eps)
    rsin = 0;
  else
    rsin = sqrt(e.r * e.r - rcos * rcos);
  Point dir = (f - e) / d;
  Point p1 = e + Point(dir.x * rcos - dir.y * rsin, dir.x * rsin + dir.y * rcos);
  Point p2 = e + Point(dir.x * rcos + dir.y * rsin, dir.x * -rsin + dir.y * rcos);
  res.push_back(p1);
  if (norm(p1 - p2) > eps) res.push_back(p2);
  return res;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment