#include <algorithm>
#include <array>
#include <bits/stdc++.h>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

// lib/rotate_left.hpp
#ifndef ROTATE_LEFT_HPP
#define ROTATE_LEFT_HPP


/*
usage:

// 5-bit circular shift to the left
tools::rotate_left(x, 5);
*/

// Source: Stack Overflow ( https://stackoverflow.com/questions/776508/best-practices-for-circular-shift-rotate-operations-in-c/776523#776523 )
// Author: John Regehr ( https://blog.regehr.org/ ) and Peter Cordes ( https://stackoverflow.com/users/224132/peter-cordes )
// License: CC BY-SA 3.0
namespace tools {
  template <typename T, typename ::std::enable_if<::std::is_unsigned<T>::value, ::std::nullptr_t>::type = nullptr>
  constexpr T rotate_left(const T& value, const ::std::size_t& count) noexcept {
    return (value << (count & ::std::numeric_limits<T>::max())) | (value >> (-(count & ::std::numeric_limits<T>::max()) & ::std::numeric_limits<T>::max()));
  }

  template <typename T, typename ::std::enable_if<::std::is_signed<T>::value, ::std::nullptr_t>::type = nullptr>
  T rotate_left(const T& value, const ::std::size_t& count) {
    return value >= static_cast<T>(0)
      ? static_cast<T>(::tools::rotate_left(static_cast<typename ::std::make_unsigned<T>::type>(value), count))
      : (throw ::std::invalid_argument("value of ::tools::rotate_left must be non-negative, but was " + ::std::to_string(value) + "."));
  }
}

#endif

// lib/util.hpp
#ifndef UTIL_HPP
#define UTIL_HPP


using i64 = ::std::int_fast64_t;
using u64 = ::std::uint_fast64_t;
using i32 = ::std::int_fast32_t;
using u32 = ::std::uint_fast32_t;

namespace tools {
  template <typename T>
  void read(::std::istream& is, ::std::vector<T>& vector, const typename ::std::vector<T>::size_type size) {
    vector.reserve(size);
    ::std::copy_n(::std::istream_iterator<T>(is), size, ::std::back_inserter(vector));
  }
  template <typename T>
  void read(::std::vector<T>& vector, const typename ::std::vector<T>::size_type size) {
    ::tools::read(::std::cin, vector, size);
  }

  template <typename T, ::std::size_t N>
  void read(::std::istream& is, ::std::array<T, N>& array) {
    ::std::copy_n(std::istream_iterator<T>(is), N, array.begin());
  }
  template <typename T, ::std::size_t N>
  void read(::std::array<T, N>& array) {
    ::tools::read(::std::cin, array);
  }
}

#endif

// lib/vector2.hpp
#ifndef VECTOR2_HPP
#define VECTOR2_HPP


/*
usage:

tools::vector2<int>(6, 5) // => (6, 5)
*/

namespace tools {
  template <typename T>
  class vector2 {
  public:
    T x;
    T y;

    vector2() :
      vector2(T(), T()) {
    }

    vector2(const T& x, const T& y) :
      x(x),
      y(y) {
    }

    double norm() const {
      return ::std::sqrt(this->squaredNorm());
    }

    T squaredNorm() const {
      return this->inner_product(*this);
    }

    template <typename SFINAE_T = T, typename ::std::enable_if<::std::is_same<SFINAE_T, double>::value, ::std::nullptr_t>::type = nullptr>
    double normalize() const {
      return *this / this->norm();
    }

    ::tools::vector2<T> operator+() const {
      return *this;
    }

    ::tools::vector2<T> operator-() const {
      return ::tools::vector2<T>(-this->x, -this->y);
    }

    friend ::tools::vector2<T> operator+(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return ::tools::vector2<T>(lhs.x + rhs.x, lhs.y + rhs.y);
    }

    friend ::tools::vector2<T> operator-(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return ::tools::vector2<T>(lhs.x - rhs.x, lhs.y - rhs.y);
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    friend ::tools::vector2<T> operator*(const ::tools::vector2<T>& lhs, const OTHER& rhs) {
      return ::tools::vector2<T>(lhs.x * rhs, lhs.y * rhs);
    }
    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    friend ::tools::vector2<T> operator*(const OTHER& lhs, const ::tools::vector2<T>& rhs) {
      return ::tools::vector2<T>(lhs * rhs.x, lhs * rhs.y);
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    friend ::tools::vector2<T> operator/(const ::tools::vector2<T>& lhs, const OTHER& rhs) {
      return ::tools::vector2<T>(lhs.x / rhs, lhs.y / rhs);
    }

    T inner_product(const ::tools::vector2<T>& other) const {
      return this->x * other.x + this->y * other.y;
    }

    ::tools::vector2<T>& operator+=(const ::tools::vector2<T>& other) {
      return *this = *this + other;
    }

    ::tools::vector2<T>& operator-=(const ::tools::vector2<T>& other) {
      return *this = *this - other;
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    ::tools::vector2<T>& operator*=(const OTHER& other) {
      return *this = *this * other;
    }

    template <typename OTHER, typename ::std::enable_if<!::std::is_same<OTHER, ::tools::vector2<T>>::value, ::std::nullptr_t>::type = nullptr>
    ::tools::vector2<T>& operator/=(const OTHER& other) {
      return *this = *this / other;
    }

    friend bool operator==(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return lhs.x == rhs.x && lhs.y == rhs.y;
    }

    friend bool operator!=(const ::tools::vector2<T>& lhs, const ::tools::vector2<T>& rhs) {
      return lhs.x != rhs.x || lhs.y != rhs.y;
    }

    static ::std::array<::tools::vector2<T>, 4> four_directions() {
      return ::std::array<::tools::vector2<T>, 4>({
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(1))
      });
    }

    static ::std::array<::tools::vector2<T>, 8> eight_directions() {
      return ::std::array<::tools::vector2<T>, 8>({
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(-1), static_cast<T>(1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(1)),
        ::tools::vector2<T>(static_cast<T>(0), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(-1)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(0)),
        ::tools::vector2<T>(static_cast<T>(1), static_cast<T>(1))
      });
    }
  };
}

namespace std {
  template <typename T>
  ::std::string to_string(const ::tools::vector2<T>& f) {
    return '(' + ::std::to_string(f.x) + ", " + ::std::to_string(f.y) + ')';
  }

  template <typename T>
  struct hash<::tools::vector2<T>> {
    using result_type = ::std::size_t;
    using argument_type = ::tools::vector2<T>;
    ::std::size_t operator()(const ::tools::vector2<T>& key) const {
      static const ::std::hash<T> hash;
      static const ::std::size_t shift = ::std::numeric_limits<::std::size_t>::digits / 2;
      const ::std::size_t hash_x = hash(key.x);
      const ::std::size_t hash_y = hash(key.y);
      return hash_x ^ ::tools::rotate_left(hash_y, shift);
    }
  };

  template <typename T>
  ::std::ostream& operator<<(::std::ostream& os, const ::tools::vector2<T>& self) {
    return os << ::std::to_string(self);
  }

  template <typename T>
  ::std::istream& operator>>(::std::istream& is, ::tools::vector2<T>& self) {
    return is >> self.x >> self.y;
  }
}

#endif

// main.cpp

int main() {
  i64 H, W, M;
  std::cin >> H >> W >> M;
  std::vector<tools::vector2<i64>> targets;
  for (i64 i = 0; i < M; ++i) {
    i64 h_i, w_i;
    std::cin >> h_i >> w_i;
    targets.emplace_back(w_i - 1, h_i - 1);
  }

  std::vector<i64> rows(H, 0);
  std::vector<i64> columns(W, 0);
  for (const tools::vector2<i64>& target : targets) {
    ++rows[target.y];
    ++columns[target.x];
  }

  std::unordered_set<i64> possible_rows;
  const i64 optimal_for_rows = *std::max_element(rows.begin(), rows.end());
  for (i64 i = 0; i < H; ++i) {
    if (rows[i] == optimal_for_rows) {
      possible_rows.emplace(i);
    }
  }

  std::unordered_set<i64> possible_columns;
  const i64 optimal_for_columns = *std::max_element(columns.begin(), columns.end());
  for (i64 i = 0; i < W; ++i) {
    if (columns[i] == optimal_for_columns) {
      possible_columns.emplace(i);
    }
  }

  i64 option_count = possible_rows.size() * possible_columns.size();
  for (const tools::vector2<i64>& target : targets) {
    if (possible_rows.find(target.y) != possible_rows.end() && possible_columns.find(target.x) != possible_columns.end()) {
      --option_count;
    }
  }

  std::cout << optimal_for_rows + optimal_for_columns - (option_count == 0 ? 1 : 0) << std::endl;
  return 0;
}

Measured memory_bytes: 39964