0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ベクトル構造体 をC++で実装してみた【競プロ用ライブラリ】

Posted at

競プロでは、ベクトルを扱う数学問題がよく出題されます。
本記事では、コピペで使えるベクトル構造体のライブラリをC++で実装します。

主な機能と計算量

名前 説明 計算量
constructor() (0,0) のベクトルを作る $O(1)$
constructor(x,y) (x,y) のベクトルを作る $O(1)$
manhat(v) v とのマンハッタン距離を返す $O(1)$
euclid(v) v とのユークリッド距離を返す $O(1)$
euclid2(v) v とのユークリッド距離の 2 乗を返す $O(1)$
rot_l_90 原点を中心に左に90度回転させる $O(1)$
rot_l_90(v) v を中心に左に90度回転させる $O(1)$
rot_l(s) 原点を中心に左に s 度回転させる(弧度法) $O(1)$
rot_l(v,s) v を中心に左に s 度回転させる(弧度法) $O(1)$
cross(v) 自分と v の外積の大きさを計算(符号付き) $O(1)$

実装したコード

template<typename T> // 座標の型
struct Vec {
    ////////////メンバ変数///////////////
    // - 通常の数学と同じように(x,y)座標系で考える
    T x,y;
    
    /////////////コンストラクタ/////////////
    Vec(): x(T(0)), y(T(0)) {}
    Vec(T x, T y): x(x), y(y) {}
    
    ////////演算子のオーバーロード/////////
    // - 足し算、引き算に関しては各座標に対して行う
    bool operator==(const Vec<T>& v) const { return tie(x, y) == tie(v.x, v.y); }
    bool operator!=(const Vec<T>& v) const { return tie(x, y) != tie(v.x, v.y); }
    Vec<T> operator+(const Vec<T>& v) const { return Vec<T>{x+v.x, y+v.y}; }
    Vec<T> operator-(const Vec<T>& v) const { return Vec<T>{x-v.x, y-v.y}; }
    Vec<T> operator*(T k) const { return Vec<T>(x*k, y*k); }
    Vec<T> operator/(T k) const { return Vec<T>(x/k, y/k); }
    
    ////////メンバ関数↓///////////
    
    //-------距離系--------
    T manhat(const Vec<T>& v) const {
        return abs(x - v.x) + abs(y - v.y);
    }
    double euclid(const Vec<T>& v) const {
        return sqrt(euclid2(v));
    }
    T euclid2(const Vec<T>& v) const {
        T dx = x - v.x;
        T dy = y - v.y;
        return dx*dx + dy*dy;
    }
    
    //---------回転系-----------
    // - 角度指定は弧度法
    // - 90度以外の回転は T=double 専用
    void rot_l_90(){
        T nx = -y;
        T ny = x;
        x = nx;
        y = ny;
    }
    void rot_l_90(const Vec<T>& v){
        Vec<T> t = *this - v; // v中心の座標空間での座標に変換
        t.rot_l_90(); // そのまま90度回転
        t = t + v; // 原点中心に戻す
        *this = t;
    }
    void rot_l(double s){
        T nx = x*cos(s) - y*sin(s);
        T ny = x*sin(s) + y*cos(s);
        x = nx;
        y = ny;
    }
    void rot_l(const Vec<T>& v, double s){
        Vec<T> t = *this - v; // v中心の座標空間での座標に変換
        t.rot_l(s); // そのままs度回転
        t = t + v; // 原点中心に戻す
        *this = t;
    }
    
    //-----演算系------
    T dot(const Vec<T>& v) const {
        return x*v.x + y*v.y;
    }
    T cross(const Vec<T>& b) const {
        return x*b.y - y*b.x;
    }
    
    //------デバッグ用------
    friend ostream& operator<<(ostream& os, const Vec<T>& v){
        return os << "(" << v.x << "," << v.y << ")";
    }
};
//よく使う型のエイリアス
using Vecll = Vec<long long>;
using Veci = Vec<int>;
using Vecd = Vec<double>;

使用例

#include<bits/stdc++.h>
using namespace std;


//--------ここにVecライブラリ---------//
//                                 //
//---------------------------------//


int main(void){
    // ベクトルを作成
    Vecll a(1,2), b(3,4);

    // ユークリッド距離(の2乗)を計算
    cout << a.euclid2(b) << endl; // 8

    // 左に90度回転
    a.rot_l_90();
    cout << a << endl;
}

注意点・Tips

  • 通常の (x,y)-座標系を想定しているので、(i,j)-座標系などで扱う場合は適宜変更が必要です
  • T が整数型の場合、rot_l は、誤差によりズレることがあります

関連リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?