import java.io.*;
import java.util.*;
try {
while (!st.hasMoreTokens()) {
if (s == null)
return null;
}
return st.nextToken();
return null;
}
}
new Thread(null,
new D
(),
"D",
1<<26).
start(); }
public void run() {
// size of tournament, wins
int[][] winsToRank = new int[20][8];
winsToRank[1][0] = 1;
winsToRank[2][0] = 2;
winsToRank[2][1] = 1;
winsToRank[4][0] = 3;
winsToRank[4][1] = 2;
winsToRank[4][2] = 1;
winsToRank[8][0] = 5;
winsToRank[8][1] = 3;
winsToRank[8][2] = 2;
winsToRank[8][3] = 1;
winsToRank[16][0] = 9;
winsToRank[16][1] = 5;
winsToRank[16][2] = 3;
winsToRank[16][3] = 2;
winsToRank[16][4] = 1;
// generate();
int CASES
= Integer.
parseInt( next
() ); int ccc = 1;
while (CASES-- > 0) {
out.println("Case #" + ccc++ + ":");
beats = new boolean[N][N];
for (int a = 0; a < N; a++) for (int b = 0; b < N; b++)
beats[a][b] = next().equals("1");
if (N == 1) {
out.println("1 1");
continue;
}
if (N == 2) {
if (beats[0][1]) {
out.println("1 1");
out.println("2 2");
} else {
out.println("2 2");
out.println("1 1");
}
continue;
}
// max number of wins a player can have in a tournament
int[] maxWins = new int[N];
// canWin(p, players) = can p win the tournament if players are playing? players is len = 2,4,8,16
Set
<Integer
>[][] canWin
= new TreeSet[N
][N
+1]; for (int p = 0; p < N; p++) for (int q = 0; q <= N; q++)
canWin[p][q] = new TreeSet<>();
for (int p = 0; p < N; p++) {
Set<Integer> result = canWin[p][2];
for (int q = 0; q < N; q++) if (q != p && beats[p][q]) {
maxWins[p] = 1;
result.add( (1<<p)|(1<<q) );
}
}
for (int players = 4, wins = 2; players <= N; players *= 2, wins++) {
loop: for (int p = 0; p < N; p++) if (!canWin[p][players/2].isEmpty()) {
Set<Integer> result = canWin[p][players];
for (int q = 0; q < N; q++) if (q != p && beats[p][q] && !canWin[q][players/2].isEmpty()) {
for (int qMatch : canWin[q][players/2]) for (int pMatch : canWin[p][players/2]) if ( (qMatch&pMatch) == 0 ) {
result.add( qMatch|pMatch );
if (players == N) {
maxWins[p] = wins;
continue loop;
}
}
}
if (!result.isEmpty()) {
maxWins[p] = wins;
}
}
}
int[] minRank = new int[N];
for (int p = 0; p < N; p++) {
int wins = 0;
for (int q = 0; q < N; q++) if (q != p && beats[p][q]) {
wins++;
}
if (wins == N-1) {
minRank[p] = 1;
continue;
}
if (N == 4) {
minRank[p] = 3;
} else if (N==8) {
minRank[p] = 5;
} else {
minRank[p] = 9;
}
}
for (int p = 0; p < N; p++) {
int wins = maxWins[p];
out.println( winsToRank[N][wins] + " " + minRank[p] );
}
}
//
out.flush();
}
void generate() {
int N = 16;
out.println(N);
int[][] val = new int[N][N];
for (int p = 0; p < N; p++) for (int q = p+1; q < N; q++) {
if (r.nextBoolean()) {
val[p][q] = 1;
} else {
val[q][p] = 1;
}
}
for (int p = 0; p < N; p++) {
for (int q = 0; q < N; q++) {
out.print(val[p][q] + " ");
}
out.println();
}
}
int N; // number of competitors
boolean[][] beats; // beats[a][b] = true if a beats b in a match
}