#include <iostream>
#include <vector>
#include <complex>

using Real = long double;
using Point = std::complex<Real>;
using Segment = std::pair<Point, Point>;
using Polygon = std::vector<Point>;

bool operator<(const Point& a, const Point& b) {
    return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}

std::istream& operator>>(std::istream& is, Point& p) {
    Real x, y;
    is >> x >> y;
    p = Point(x, y);
    return is;
}

const Real EPS = 1e-10;
const Point origin(0, 0);

// 宇宙船演算子
inline int compare(Real a, Real b) {
    if (std::abs(a - b) < EPS) return 0;
    return a - b > 0 ? 1 : -1;
}

inline Real dist(Point a, Point b) {
    return std::abs(a - b);
}

inline Real length(Segment s) {
    return dist(s.first, s.second);
}

// inner product
inline Real dot(Point x, Point y) {
    return std::real(std::conj(x) * (y));
}

// outer product
inline Real cross(Point x, Point y) {
    return std::imag(std::conj(x) * (y));
}

// lに対するpの位置
// 0: on segment
// 1: counter clockwise  -1: clockwise
// 2: online front       -2: online back
int side(Segment s, Point p) {
    Real c = cross(s.second - s.first, p - s.first);
    if (compare(c, 0) != 0) return compare(c, 0);

    Real d = dot(s.second - s.first, p - s.first);
    if (compare(d, 0) < 0) return -2;

    return (compare(length(Segment(s.first, p)), length(s)) > 0 ? 2 : 0);
}

// 平行判定
inline bool isparallel(Segment s1, Segment s2) {
    return compare(cross(s1.second - s1.first, s2.second - s2.first), 0) == 0;
}

// 線分の交差判定
// bound: 線分の端点を含むか
inline bool intersect(Segment s1, Segment s2, bool bound) {
    return (side(s1, s2.first) * side(s1, s2.second) < bound) &&
           (side(s2, s1.first) * side(s2, s1.second) < bound);
}

// 線分の交点
Point intersection(Segment s1, Segment s2) {
    Real c1 = cross(s2.second - s2.first, s1.second - s1.first);
    Real c2 = cross(s2.second - s2.first, s1.first - s2.first);
    return s1.first + (s1.second - s1.first) * (-c2 / c1);
}


using namespace std;

int main() {
    int N, M;
    cin >> N >> M;

    vector<Polygon> gs(N);
    for (auto& g : gs) {
        int L;
        cin >> L;
        g.resize(L);
        for (auto& p : g) cin >> p;
    }

    vector<Point> people(M);
    for (auto& p : people) cin >> p;

    // 有権者と障害物の頂点を結ぶ直線を列挙
    vector<Segment> segs;
    for (auto p : people) {
        for (auto& g : gs) {
            for (auto q : g) {
                segs.emplace_back(p, q);
            }
        }
    }

    // 上で列挙した直線同士の交点を列挙
    vector<Point> stand;
    for (int i = 0; i < segs.size(); ++i) {
        for (int j = i + 1; j < segs.size(); ++j) {
            if (!isparallel(segs[i], segs[j])) {
                stand.push_back(intersection(segs[i], segs[j]));
            }
        }
    }

    int ans = 0;
    for (auto p : stand) {
        int cnt = 0;

        for (auto q : people) {
            Segment s(p, q);
            bool judge = true;
            for (auto& g : gs) {
                for (int i = 0; i < g.size(); ++i) {
                    // 多角形の辺と線分が端点を除いて交差するか？
                    if (intersect(s, Segment(g[i], g[(i + 1) % g.size()]), false)) judge = false;
                }
            }
            if (judge) ++cnt;
        }

        ans = max(ans, cnt);
    }

    cout << ans << endl;
    return 0;
}



Measured memory_bytes: 3644