// Arup Guha
// 11/12/2012
// Solution to 2012 South East Regional (D1) Problem J: Walls

// The basic idea here is to try all combinations of walls by X, and then use
// a greedy strategy to draw the y walls. Basically, you only draw one right before
// two points will be in the same chamber.

import java.util.*;

public class walls {

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);

		int n = stdin.nextInt();

		while (n!= 0) {

			// Read in the points
			point[] P = new point[n];
			for (int i=0; i<n; i++) {
				int x = stdin.nextInt();
				int y = stdin.nextInt();
				P[i] = new point(x,y);
			}

			// This sorts them by X.
			Arrays.sort(P);

			// These lists store the needed X walls and their corresponding indexes.
			ArrayList<Integer> diffX = new ArrayList<Integer>();
			ArrayList<Integer> indexList = new ArrayList<Integer>();

			// Add a new X wall whenever two successive points have different X coordinates.
			for (int i=0; i<n-1; i++) {
				if (P[i].x != P[i+1].x && (diffX.size()==0 || diffX.get(diffX.size()-1) != P[i+1].x-1)) {
					diffX.add(P[i+1].x-1);
					indexList.add(i+1);
				}
			}

			// Number of possible X walls.
			int xLines = diffX.size();

			int best = 100;

			// Try subset i.
			for (int i=0; i < (1 << xLines); i++) {

				// Sometimes this set of X walls makes a solution impossible. Screen these situations out.
				if (solve2(P, diffX, makeList(indexList,i))) {

					// If this is solvable, split by Y.
					int value = solve(P, diffX, makeList(indexList,i));
					if (value < best)
						best = value;
				}
			}

			System.out.println(best);
			n = stdin.nextInt();
		}

	}

	// Creates a list of X values based on the bitmask mask.
	public static ArrayList<Integer> makeList(ArrayList<Integer> list, int mask) {

		// Usual technique to list a subset of items in list and return the corresponding list.
		ArrayList<Integer> ans = new ArrayList<Integer>();
		int index = 0;
		while (mask > 0) {
			if ((mask & 1) == 1) {
				ans.add(list.get(index));
			}
			mask = mask >> 1;
			index++;
		}
		return ans;
	}

	// Returns true, if this X split is solvable.
	public static boolean solve2(point[] P, ArrayList<Integer> diffX, ArrayList<Integer> indexList) {

		// Each entry in this array stores the points in each "chamber."
		int n = diffX.size() + 1;
		ArrayList[] ptsByX = new ArrayList[n];

		for (int i=0; i<indexList.size(); i++) {

			int start = 0;
			if (i > 0)
				start = indexList.get(i-1);
			ptsByX[i] = new ArrayList<point>();

			// These are the points to add in this chamber.
			for (int j=start; j<indexList.get(i); j++)
				ptsByX[i].add(P[j]);
		}

		// Copy in the last chamber, after the last wall.
		ptsByX[n-1] = new ArrayList<point>();
		int start = 0;
		if (indexList.size() > 0)
			start = indexList.get(indexList.size()-1);
		for (int i=start; i<P.length; i++)
			ptsByX[n-1].add(P[i]);

		// Loop through each chamber.
		for (int i=0; i<n; i++) {

			if (ptsByX[i] != null) {

				// Just do a brute force check to see if any of these have the same 2 Y values, which would make
				// splitting this chamber by Y impossible.
				for (int j=0; j<ptsByX[i].size(); j++) {
					for (int k=j+1; k<ptsByX[i].size(); k++) {
						if (((ArrayList<point>)ptsByX[i]).get(j).y == ((ArrayList<point>)ptsByX[i]).get(k).y)
							return false;
					}
				}
			}
		}

		// This set is solvable.
		return true;

	}

	// Runs the greedy algorithm for the points using the X walls specified by indexList.
	public static int solve(point[] P, ArrayList<Integer> diffX, ArrayList<Integer> indexList) {

		// Number of chambers.
		int n = indexList.size() + 1;

		// Copy in these chambers.
		ArrayList[] ptsByX = new ArrayList[n];
		for (int i=0; i<indexList.size(); i++) {

			int start = 0;
			if (i > 0)
				start = indexList.get(i-1);
			ptsByX[i] = new ArrayList<point>();

			for (int j=start; j<indexList.get(i); j++)
				ptsByX[i].add(P[j]);
		}

		// Add the last chamber.
		ptsByX[n-1] = new ArrayList<point>();
		int start = 0;
		if (indexList.size() > 0)
			start = indexList.get(indexList.size()-1);
		for (int i=start; i<P.length; i++)
			ptsByX[n-1].add(P[i]);

		// Need to resort each list by y.
		for (int i=0; i<n; i++) {
			sort((ArrayList<point>)ptsByX[i]);
		}

		// This is how many walls we've already drawn.
		int cnt = indexList.size();

		// Consider drawing each wall, in order, only drawing when we're forced to.
		for (int myy=1; myy<36; myy+=2) {

			boolean drew = false;

			// Go through each chamber.
			for (int i=0; i<ptsByX.length; i++) {

				// If the next point will cause this chamber to have two points, we have to draw the line.
				if (ptsByX[i] != null && ptsByX[i].size() >= 2 && ((ArrayList<point>)ptsByX[i]).get(1).y - 1 ==  myy) {
					ptsByX[i].remove(0);
					cnt++;
					drew = true;
					break;
				}
			}

			// Now that we've drawn the line, remove all points below the line that are cut off by this line.
			if (drew) {
				for (int i=0; i<ptsByX.length; i++) {
					while (ptsByX[i] != null && ptsByX[i].size()>0 &&((ArrayList<point>)ptsByX[i]).get(0).y < myy)
						ptsByX[i].remove(0);
				}
			}

		}

		// Total number of walls for this configuration.
		return cnt;
	}

	// Bubble sort by y value...
	public static void sort(ArrayList<point> list) {

		for (int i=list.size()-1; i>0; i--) {
			for (int j=0; j<i; j++) {

				// Switch if out of order...
				if (list.get(j).y > list.get(j+1).y) {
					point temp = list.get(j);
					list.set(j, list.get(j+1));
					list.set(j+1, temp);
				}
			}
		}
	}
}

// Used to sort the points by X value at first.
class point implements Comparable<point> {

	public int x;
	public int y;

	public point(int myX, int myY) {
		x = myX;
		y = myY;
	}

	public int compareTo(point other) {
		if (this.x != other.x)
			return this.x - other.x;
		return this.y - other.y;
	}

}