// Arup Guha
// 5/13/2024
// Solution to 2023 SER D1 Problem C: Cramming for Finals

// Note: I came super close to the time limit, probably because of my tree based
//       segment tree and just using basic Java stuff in general.

import java.util.*;

public class c {
	
	public static int r;
	public static int c;
	public static int d;
	public static int n;
	public static pt[] locs;
	
	public static void main(String[] args) {
	
		Scanner stdin = new Scanner(System.in);
		r = stdin.nextInt();
		c = stdin.nextInt();
		d = stdin.nextInt();
		n = stdin.nextInt();
		locs = new pt[n];
		boolean swap = r > c;
		
		// Read points.
		for (int i=0; i<n; i++) {
			int x = stdin.nextInt()-1;
			int y = stdin.nextInt()-1;
			if (swap) {
				int tmp = x;
				x = y;
				y = tmp;
			}
			locs[i] = new pt(x, y);
		}
		
		// Makes sure r <= c. 
		if (swap) {
			int tmp = r;
			r = c;
			c = tmp;
		}

		// Ta da!
		System.out.println(solve());
	}
	
	public static int solve() {
		
		// Grid is too big not to have a blank space for you.
		if (numLocs() > n) return 0;
		
		// We will store ranges for row values 0 through r-1.
		ArrayList<range>[] ranges = new ArrayList[r];
		for (int i=0; i<r; i++) ranges[i] = new ArrayList<range>();
		ArrayList<Integer>[] yvals = new ArrayList[r];
		for (int i=0; i<r; i++) yvals[i] = new ArrayList<Integer>();
		
		// Go through each point.
		for (int i=0; i<n; i++) {
			
			// We can't sit here!
			yvals[locs[i].x].add(locs[i].y);
			
			// Scan through each possible "row" value.
			for (int j=Math.max(0,locs[i].x-d); j<=Math.min(locs[i].x+d, r-1); j++) {
				int sqleft = d*d - (locs[i].x-j)*(locs[i].x-j);
				int delta = (int)(Math.sqrt(sqleft+.01));
				ranges[j].add(new range(Math.max(0,locs[i].y-delta), Math.min(c-1,locs[i].y+delta)));
			}
		}
		
		// Seg Tree of size c.
		IntTree segtree = new IntTree(0, c-1);
		int res = n;
		
		for (int i=0; i<r; i++) {
			
			// Undo last set of changes.
			if (i > 0) {
				
				// These were covered ranges before, so we undo these.
				for (range myr : ranges[i-1]) 
					segtree.change(myr.lo, myr.hi, -1);
			
				// Undo this craziness for future columns.
				for (Integer y: yvals[i-1])
					segtree.change(y, y, -10000);
			}
			
			// Update these ranges on this row.
			for (range myr: ranges[i])
				segtree.change(myr.lo, myr.hi, 1);
			
			// This makes sure we never pick a place a student is sitting.
			for (Integer y: yvals[i])
				segtree.change(y, y, 10000);
			
			// Update and get out if we get 0.
			res = Math.min(res, segtree.query(0, c-1));
			if (res == 0) break;
		}
		
		// Ta da!
		return res;
	}
	
	public static long numLocs() {
		
		// Makes big squares of size 2d+1 by 2d+1.
		long dim1 = (r + 2*d)/(2*d+1);
		long dim2 = (c + 2*d)/(2*d+1);
		
		// Returns how many of these squares (or partial) there are.
		return dim1*dim2;
	}

}

class pt {
	
	public int x;
	public int y;
	
	public pt(int myx, int myy) {
		x = myx;
		y = myy;
	}
}

class range {
	
	public int lo;
	public int hi;
	
	public range(int mylo, int myhi) {
		lo = mylo;
		hi = myhi;
	}
}

class IntTree {

	// Stores range for this node.
	public int low;
	public int high;

	// Stores aggregate data for this node.
	public int delta;
	public int min;

	// Pointers to children.
	public IntTree left;
	public IntTree right;

	// Creates an interval tree from myLow to myHigh, inclusive.
	public IntTree(int myLow, int myHigh) {

		low = myLow;
		high = myHigh;
		delta = 0;
		min = 0;

		// Lowest level.
		if (low == high) {
			left = null;
			right = null;
		}

		// Must create more nodes.
		else {
			int mid = (low+high)/2;
			left = new IntTree(low, mid);
			right = new IntTree(mid+1, high);
		}
	}

	// Propogates a change down to child nodes.
	public void prop() {

		// Recursive case, push down.
		if (left != null) {
			left.delta += delta;
			right.delta += delta;
			delta = 0;
		}
	}

	// Pre-condition: delta is 0.
	public void update() {
		if (left != null) {
			min = Math.min(left.min+left.delta, right.min+right.delta);
		}
	}

	// Changes the values in the range [start, end] by "adding" extra.
	public void change(int start, int end, int extra) {

		// Out of range.
		if (high < start || end < low) return;

		// Push down delta.
		prop();

		// Whole range must be updated.
		if (start <= low && high <= end) {
			delta += extra;
			update();
			return;
		}

		// Portions of children have to be changed instead.
		left.change(start, end, extra);
		right.change(start, end, extra);
		update();
	}

	public int query(int start, int end) {

		// Out of range.
		if (high < start || end < low) return Integer.MAX_VALUE;

		// Whole range must be returned;
		if (start <= low && high <= end) {
			return min+delta;
		}

		// Get answers from both potions.
		prop();
		int l = left.query(start, end);
		int r = right.query(start, end);
		update();
		return Math.min(l, r);
	}
}