// TTarget.cc
// TF solution to Target
// 2007 ECNA

#include <iostream>
using namespace std;

const int MAXPTS = 66;
const int MAXLINES = MAXPTS * MAXPTS;

struct {
  int x,y,z;
} Pts[MAXPTS];

int Lines[MAXLINES][MAXPTS];
int NumLines, NumPts;
int Best, X[MAXLINES];

void PrintPts(){
 for(int i=1;i<=NumPts;i++)
  cout<<"point "<<i<<':'<<Pts[i].x<<','<<Pts[i].y<<','<<Pts[i].z<<endl;
}

void GetPts(){
 for(int i=1;i<=NumPts;i++)
  cin>>Pts[i].x>>Pts[i].y>>Pts[i].z;
}

void Print3Lines(){
  cout<<"Lines="<<NumLines<<endl;
  for(int i=1;i<=NumLines;i++){
   for(int j=1;j<=NumPts;j++)
    if(Lines[i][j]) cout<<j<<' ';
   cout<<endl;
  }
}

int Half(int n){
  if(n % 2)   //n is odd
    return n/2 + 1;
  else
    return n/2;
}

int CalculateLines(){
  int PtsUsed=0, PtsCovered[MAXPTS], LinesUsed=0;
  int PtsUnused;

  for(int i=1;i<=NumPts;i++) PtsCovered[i]=0;

  //mark pts on used lines
  for(int i=1;i<=NumLines;i++)
   if(X[i]){    //if line i is used
    LinesUsed++;
    for(int j=1;j<=NumPts;j++)
     if(Lines[i][j]) PtsCovered[j]=1;   //mark pt j as covered
   }
  //count # of pts covered
  for(int i=1;i<=NumPts;i++)
   if(PtsCovered[i]) PtsUsed++;
  PtsUnused = NumPts - PtsUsed;

/*
cout<<"calculating: X:";
for(int i=1;i<=NumLines;i++) cout<<X[i];
cout<<" pts: ";
for(int i=1;i<=NumPts;i++) cout<<PtsCovered[i];
cout<<endl;
*/

  //total lines needed
  return (LinesUsed + Half(PtsUnused));

}

int PtsLeftOnLine(int k){
  int count=0;
  for(int i=1;i<=NumPts;i++)
   if(Lines[k][i]){
    count++;
    for(int j=1;j<k;j++)
     if(Lines[j][i]){
      count--;
      break;
     }
   }
 return count;
}

void FindAllSubsets(int k){
  int L;

  for(int i=1;i>=0;i--){
   if(!(i==1 && PtsLeftOnLine(k)<3)){
   X[k]=i;
   if(k==NumLines){
    L = CalculateLines();
//cout<<"L="<<L<<endl;
    if(L<Best) Best = L;
   }
   else
    FindAllSubsets(k+1);
  }
  }
}

void Cover(){
  if(NumLines==0) cout<<Half(NumPts);
  else {
   Best = Half(NumPts);
   FindAllSubsets(1);    //backtrac to find all subsets of 3 lines
   cout<<Best;
  }
}

void Make3Lines(){
 bool First3Lines;
 int delx, dely,delz, delx1, dely1, delz1;
 int Used[MAXPTS][MAXPTS];

 for(int i=1;i<=NumPts;i++)
  for(int j=1;j<=NumPts;j++)
   Used[i][j]=0;

 NumLines=0;
 for(int i=1;i<=NumPts-2;i++)
  for(int j=i+1;j<=NumPts-1;j++)
   if(Used[i][j]==0){   //i & j not on same line before this
    First3Lines = true;
    delx = Pts[i].x - Pts[j].x;
    dely = Pts[i].y - Pts[j].y;
    delz = Pts[i].z - Pts[j].z;
    for(int k=j+1;k<=NumPts;k++){
     delx1 = Pts[i].x - Pts[k].x;
     dely1 = Pts[i].y - Pts[k].y;
     delz1 = Pts[i].z - Pts[k].z;
//cout<<"del vals "<<delx<<' '<<dely<<' '<<delz<<' '<<delx1<<' '<<dely1<<' '<<delz1<<endl;
     //see if k on same line as i & j
     if(delx*dely1==delx1*dely && 
        delx*delz1==delx1*delz &&
        dely*delz1==dely1*delz){
//cout<<delx<<' '<<dely<<' '<<delz<<' '<<delx1<<' '<<dely1<<' '<<delz1<<endl;
      if(First3Lines){  //start new line
       First3Lines = false;
       NumLines++;
       for(int m=1;m<=NumPts;m++) Lines[NumLines][m]=0;
       Lines[NumLines][i] = Lines[NumLines][j] = 1;
       Used[i][j]=Used[j][i]=1;
      }
      Lines[NumLines][k] = 1;  //put k on the line
      // mark all other pts on this lines
      for(int m=1;m<=NumPts;m++) 
       if(Lines[NumLines][m])
        Used[m][k]=Used[k][m]=1;
     }
    }
   }
}


int main(){
  int Case=1;

  cin>>NumPts;
  while(NumPts>0){
   GetPts();
//PrintPts();
   Make3Lines();
//Print3Lines();
   cout<<"Target set "<< Case++<<" can be cleared using only ";
   Cover();
   cout<<" shots."<<endl;

   cin>>NumPts;
  }

 return 0;
}

