#include <iostream>
using namespace std;

const int MAX=1000;

struct point
{
	int x, y, z;
} b[MAX];		// balloon locations

struct line
{
	point start;
	int delx, dely, delz;
	int n;		// number of balloons hit by line (>=3)
	int *list;	// list of balloons
} lines[MAX/3];
int nlines;

int minLines;		// minimum number of lines used (set in bestCover) 

bool onLine(point p, line l)
{
	int dx = p.x-l.start.x;
	int dy = p.y-l.start.y;
//cout << "     dx, dy = " << dx << ',' << dy << endl;
//cout << " delx, dely = " << l.delx << ',' << l.dely << endl;
	if (dx*l.dely != dy*l.delx)
		return false;
	int dz = p.z-l.start.z;
	if (dz*l.dely != dy*l.delz)
		return false;
//cout << "     dx, dz = " << dx << ',' << dz << endl;
//cout << " delx, delz = " << l.delx << ',' << l.delz << endl;
	return (dx*l.delz == dz*l.delx);
}

void getLines(int n)	// determine lines which pass through 3 or more balloons
{
	int i, j, k;
	int list[MAX], count;

	nlines = 0;
	for(i=0; i<n-2; i++) {
		list[0] = i;
		for(j=i+1; j<n-1; j++) {
			list[1] = j;
			count = 2;
			point p = b[j];
			lines[nlines].start = b[i];
			lines[nlines].delx = p.x-lines[nlines].start.x;
			lines[nlines].dely = p.y-lines[nlines].start.y;
			lines[nlines].delz = p.z-lines[nlines].start.z;
			bool found=false;
			for(k=0; k<n; k++) {
//cout << "checking " << i << ',' << j << ',' << k << endl;
				if (onLine(b[k], lines[nlines])) {
					if (k == i || k == j)
						continue;
					else if (k<j)
						break;	// already found this line
					else  {
						found = true;
						list[count++] = k;
					}
				}
			}
			if (found) {
//cout << "found line through balloons";
				lines[nlines].n = count;
				lines[nlines].list = new int[count];
				for(k=0; k<count; k++) {
					lines[nlines].list[k] = list[k];
//cout << " " << list[k];
				}
					// insert new line in sorted order
					//    (dicreasing by # of balloons in line)
				for(k=nlines-1; k>=0; k--) {
					if (lines[k+1].n < lines[k].n)
						break;
					line temp = lines[k+1];
					lines[k+1] = lines[k];
					lines[k] = temp;
				}
//cout << endl;
				nlines++;
			}
		}
	}
}

void bestCover(int i, int numL, int numB, int hits[], int cover, int linesUsed)
{
//cout << "i, cover, linesUsed" << i << ',' << cover << ',' << linesUsed << endl;
	int j;

	if (i == numL || numB-cover <=2) {	
		if (linesUsed + (numB-cover+1)/2 < minLines) {
			minLines = linesUsed + (numB-cover+1)/2;
		}
	}
	else if (linesUsed + (numB-cover)/lines[i].n >= minLines)
		return;
	else {
				// use line i;
		int newHits=0;
		for(j=0; j<lines[i].n; j++) {
			hits[lines[i].list[j]]++;
			if (hits[lines[i].list[j]] == 1)
				newHits++;
		}
		bestCover(i+1, numL, numB, hits, cover+newHits, linesUsed+1);
		for(j=0; j<lines[i].n; j++) {
			hits[lines[i].list[j]]--;
		}
				// don't use line i;
		bestCover(i+1, numL, numB, hits, cover, linesUsed);
	}
}
	
int main()
{
	int i, n, icase=0;;

	cin >> n;
	while (n != 0) {
		icase++;
		int *hits = new int[n];
		for(i=0; i<n; i++) {
			cin >> b[i].x >> b[i].y >> b[i].z;
			hits[i] = 0;
		}
		getLines(n);
//for(i=0; i<nlines; i++) {
//cout << lines[i].n << ":";
//for(int j=0; j<lines[i].n; j++)
//cout << " " << lines[i].list[j];
//cout << endl;
//}
		minLines = (n+1)/2;
		bestCover(0, nlines, n, hits, 0, 0);
		cout << "Target set " << icase << " can be cleared using only " << minLines << " shots." << endl;

		cin >> n;
	}
	return 0;
}

