import java.io.*;
import java.util.*;
public class Main {
static int N; // 격자의 크기 (N x N)
static int[][] grid; // 지도 정보 (0: 집없음, 1: 집있음)
static boolean[][] visited; // 방문 여부 체크 배열
// 상하좌우 4방향 이동 정의 배열
static int[][] directions = {
{-1, 0}, // 위로 한 칸
{1, 0}, // 아래로 한 칸
{0, -1}, // 왼쪽으로 한 칸
{0, 1} // 오른쪽으로 한 칸
};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
// visited와 grid 배열을 N×N 크기로 초기화
visited = new boolean[N][N];
grid = new int[N][N];
// N 줄에 걸쳐 격자-지도를 한 줄씩 읽어서 grid 배열 채우기
// 입력된 문자 '0' 또는 '1'을 정수 0 또는 1로 변환해 grid[i][j]에 저장
for (int i = 0; i < N; i++) {
String line = br.readLine();
for (int j = 0; j < N; j++) {
grid[i][j] = line.charAt(j) - '0';
}
}
// componentSizes: 발견된 각 단지(component)에 속한 집 수를 순서대로 저장
List<Integer> componentSizes = new ArrayList<>();
/*
* 모든 칸을 순회하며,
* 집(1)이면서 아직 방문하지 않은 칸을 찾으면
* dfs로 새로운 단지에 속한 집 개수를 세어
* houseCount에 받고,
* componentSizes에 추가한다.
*/
for (int row = 0; row < N; row++) {
for (int col = 0; col < N; col++) {
if (grid[row][col] == 1 && !visited[row][col]) {
int houseCount = dfs(row, col);
componentSizes.add(houseCount);
}
}
}
// 단지별 집 개수 오름차순 정렬
Collections.sort(componentSizes);
// 결과 출력
System.out.println(componentSizes.size());
for (int size : componentSizes) {
System.out.println(size);
}
}
/*
* dfs: (row, col)에서 시작해
* 상하좌우로 연결된 모든 집(값 1)을 깊이 우선 탐색으로 방문 처리하고,
* 해당 component에 속한 집 개수(houseCount)를 반환
*/
static int dfs(int row, int col) {
visited[row][col] = true; // 현재 칸 방문 처리
int houseCount = 1; // 현재 칸에 있는 집 1채 카운트
// 4방향 하나씩 확인하며 재귀 호출
for (int[] dir : directions) {
int newRow = row + dir[0];
int newCol = col + dir[1];
if (newRow >= 0 && newRow < N && newCol >= 0 && newCol < N) {
if (!visited[newRow][newCol] && grid[newRow][newCol] == 1) {
houseCount += dfs(newRow, newCol);
}
}
}
// 이 단지에 속한 집의 최종 개수를 반환
return houseCount;
}
}