Let's consider an n × n square matrix, consisting of digits one and zero.We'll consider a matrix good, if it meets the following condition: in each row of the matrix all ones go in one group. That is, each row of the matrix looks like that 00...0011...1100...00 (or simply consists of zeroes if it has no ones).You are given matrix a of size n × n, consisting of zeroes and ones. Your task is to determine whether you can get a good matrix b from it by rearranging the columns or not.

The first line contains integer n (1 ≤ n ≤ 500) — the size of matrix a. Each of n following lines contains n characters "0" and "1" — matrix a. Note that the characters are written without separators.

Print "YES" in the first line, if you can rearrange the matrix columns so as to get a good matrix b. In the next n lines print the good matrix b. If there are multiple answers, you are allowed to print any of them. If it is impossible to get a good matrix, print "NO".

//package round150;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Set;

public class E {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni();
		char[][] map = nm(n,n);

		Node root = universal(n);
		for(int i = 0;i < n;i++){
			Set<Integer> set = new HashSet<>();
			for(int j = 0;j < n;j++){
				if(map[i][j] == '1'){
					set.add(j);
				}
			}
			root = reduce(root, set);
		}
		if(root == null){
			out.println("NO");
		}else{
			out.println("YES");
			List<Integer> f = root.frontier();
			for(int i = 0;i < n;i++){
				for(int j = 0;j < n;j++){
					out.print(map[i][f.get(j)]);
				}
				out.println();
			}
		}
	}

	public static enum NodeType
	{
		LEAF, P, Q;
	}

	public static class Node
	{
		public NodeType type; // 0=leaf, 1=P, 2=Q
		public int id;
		public List<Node> children;

		public Node(int id) {
			this.type = NodeType.LEAF;
			this.id = id;
		}

		public Node(NodeType type, List<Node> children) {
			this.type = type;
			this.children = children;
		}

		public Node reverse()
		{
			for(int i = 0, j = children.size()-1;i < j;i++,j--){
				Node L = children.get(i);
				Node R = children.get(j);
				children.set(j, L);
				children.set(i, R);
			}
			return this;
		}

		public List<Integer> frontier()
		{
			List<Integer> ret = new ArrayList<Integer>();
			return frontierdfs(ret);
		}

		private List<Integer> frontierdfs(List<Integer> f)
		{
			if(this.type == NodeType.LEAF){
				f.add(this.id);
				return f;
			}else{
				for(Node c : this.children)c.frontierdfs(f);
				return f;
			}
		}

		@Override
		public String toString() {
			if(type == NodeType.LEAF){
				return "" + id;
			}else if(type == NodeType.P){
				StringBuilder sb = new StringBuilder("(");
				assert this.children.size() >= 1;
				for(Node c : this.children){
					sb.append(c.toString());
					sb.append(",");
				}
				sb.deleteCharAt(sb.length()-1);
				sb.append(")");
				return sb.toString();
			}else{
				StringBuilder sb = new StringBuilder("[");
				assert this.children.size() >= 1;
				for(Node c : this.children){
					sb.append(c.toString());
					sb.append(",");
				}
				sb.deleteCharAt(sb.length()-1);
				sb.append("]");
				return sb.toString();
			}
		}
	}

	public static Node universal(int n)
	{
		Node root = new Node(NodeType.P, new ArrayList<Node>());
		for(int i = 0;i < n;i++)root.children.add(new Node(i));
		return root;
	}

	public static Node reduce(Node root, Set<Integer> S)
	{
		if(root == null)return null;
		try{
			DFSResult res = dfs(root, S);
			return res.node;
		}catch(NoMatchError e){
			return null;
		}
	}

	@SuppressWarnings("serial")
	private static class NoMatchError extends Error{};

	private static class DFSResult
	{
		Node node;
		int nins;
		int des;
		boolean nomore;

		public DFSResult(Node node, int nins, int des, boolean nomore) {
			this.node = node;
			this.nins = nins;
			this.des = des;
			this.nomore = nomore;
		}
	}

	public static DFSResult dfs(Node root, Set<Integer> S)
	{
		if(root.type == NodeType.LEAF){
			int ins = S.contains(root.id) ? 1 : 0;
			return new DFSResult(root, ins, 1, ins == S.size());
		}else if(root.type == NodeType.P){
			List<Node> fulls = new ArrayList<>();
			List<Node> empties = new ArrayList<>();
			List<Node> partials = new ArrayList<>();
			int nins = 0;
			int des = 0;
			for(int i = 0;i < root.children.size();i++){
				DFSResult res = dfs(root.children.get(i), S);
				root.children.set(i, res.node);
				if(res.nomore)return new DFSResult(root, -1, -1, true);
				nins += res.nins;
				des += res.des;
				if(res.nins == res.des){
					fulls.add(res.node);
				}else if(res.nins == 0){
					empties.add(res.node);
				}else{
					partials.add(res.node);
					if(partials.size() > 2)throw new NoMatchError();
				}
			}
			if(fulls.size() == root.children.size()){
				return new DFSResult(root, nins, des, nins == S.size());
			}
			if(empties.size() == root.children.size()){
				return new DFSResult(root, 0, des, nins == S.size());
			}
			if(nins == S.size()){
				// root = ROOT(T,S)
				if(partials.isEmpty()){
					if(fulls.size() > 1){
						root.children = empties;
						Node f = new Node(NodeType.P, fulls);
						root.children.add(f);
					}
				}else if(partials.size() == 1){
					assert partials.get(0).type == NodeType.Q;
					if(fulls.size() >= 1){
						root.children = empties;
						root.children.addAll(partials);
						Node f = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
						partials.get(0).children.add(f); // E-F
						if(root.children.size() == 1){
							root = partials.get(0);
						}
					}
				}else if(partials.size() == 2){
					assert partials.get(0).type == NodeType.Q;
					assert partials.get(1).type == NodeType.Q;
					root.children = empties;
					root.children.add(partials.get(0));
					if(fulls.size() >= 1){
						Node f = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
						partials.get(0).children.add(f); // E-F
					}
					partials.get(0).children.addAll(partials.get(1).reverse().children);
				}
			}else{
				if(partials.isEmpty()){
					Node L = empties.size() > 1 ? new Node(NodeType.P, empties) : empties.get(0);
					Node R = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
					Node ret = new Node(NodeType.Q, new ArrayList<Node>());
					ret.children.add(L);
					ret.children.add(R);
					root = ret;
				}else if(partials.size() == 1){
					assert partials.get(0).type == NodeType.Q;
					Node ret = partials.get(0);
					if(empties.size() >= 1){
						Node e = empties.size() > 1 ? new Node(NodeType.P, empties) : empties.get(0);
						ret.children.add(0, e);
					}
					if(fulls.size() >= 1){
						Node f = fulls.size() > 1 ? new Node(NodeType.P, fulls) : fulls.get(0);
						ret.children.add(f);
					}
					root = ret;
				}else if(partials.size() == 2){
					throw new NoMatchError();
				}
			}

			return new DFSResult(root, nins, des, nins == S.size());
		}else if(root.type == NodeType.Q){
			List<Node> fulls = new ArrayList<>();
			List<Node> empties = new ArrayList<>();
			List<Node> partials = new ArrayList<>();
			int nins = 0;
			int des = 0;
			// EEPFFPEE
			DFSResult[] ress = new DFSResult[root.children.size()];
			int firstF = -1;
			int lastF = -1;
			int lastP = -1;
			for(int i = 0;i < root.children.size();i++){
				DFSResult res = dfs(root.children.get(i), S);
				root.children.set(i, res.node);
				if(res.nomore)return new DFSResult(root, -1, -1, true);
				nins += res.nins;
				des += res.des;
				ress[i] = res;

				if(res.nins == res.des){
					if(firstF == -1)firstF = i;
					lastF = i;
					fulls.add(res.node);
				}else if(res.nins == 0){
					empties.add(res.node);
				}else{
					lastP = i;
					partials.add(res.node);
					if(partials.size() > 2)throw new NoMatchError();
				}
			}

			// validation
			if(firstF != -1){
				// FFF
				if(lastF - firstF + 1 != fulls.size())throw new NoMatchError();
				int np = 0;
				if(firstF - 1 >= 0 && ress[firstF-1].nins > 0)np++;
				if(lastF + 1 < root.children.size() && ress[lastF + 1].nins > 0)np++;
				if(np != partials.size())throw new NoMatchError();
			}else if(lastP != -1){
				if(partials.size() == 2 && !(lastP - 1 >= 0 && ress[lastP - 1].nins > 0))throw new NoMatchError();
			}

			if(fulls.size() == root.children.size()){
				return new DFSResult(root, nins, des, nins == S.size());
			}
			if(empties.size() == root.children.size()){
				return new DFSResult(root, 0, des, nins == S.size());
			}

			if(nins == S.size()){
				// root = ROOT(T,S)
				if(partials.isEmpty()){
					// as is
				}else if(partials.size() == 1){
					assert partials.get(0).type == NodeType.Q;
					if(fulls.size() >= 1){
						if(lastP == firstF - 1){
							root.children.remove(lastP);
							root.children.addAll(lastP, partials.get(0).children); // E-F
						}else{
							root.children.remove(lastP);
							root.children.addAll(lastP, partials.get(0).reverse().children); // F-E
						}
					}
				}else if(partials.size() == 2){
					assert partials.get(0).type == NodeType.Q;
					assert partials.get(1).type == NodeType.Q;
					int firstP = lastP - fulls.size() - 1;
					root.children.remove(lastP);
					root.children.addAll(lastP, partials.get(1).reverse().children); // F-E
					root.children.remove(firstP);
					root.children.addAll(firstP, partials.get(0).children); // E-F
				}
			}else{
				if(firstF == -1){
					// partial only
					if(partials.size() == 1){
						if(lastP == 0){
							root.reverse();
							int ind = root.children.size()-1;
							root.children.remove(ind);
							root.children.addAll(ind, partials.get(0).children); // E-F
						}else if(lastP == root.children.size()-1){
							int ind = root.children.size()-1;
							root.children.remove(ind);
							root.children.addAll(ind, partials.get(0).children); // E-F
						}else{
							throw new NoMatchError();
						}
					}else{
						throw new NoMatchError();
					}
				}else if(firstF == 0){
					root.reverse();
					if(partials.size() == 1){
						int ind = root.children.size() - 1 - lastP;
						root.children.remove(ind);
						root.children.addAll(ind, partials.get(0).children); // E-F
					}else if(partials.size() > 1){
						throw new NoMatchError();
					}
				}else if(lastF == root.children.size() - 1){
					if(partials.size() == 1){
						int ind = lastP;
						root.children.remove(ind);
						root.children.addAll(ind, partials.get(0).children); // E-F
					}else if(partials.size() > 1){
						throw new NoMatchError();
					}
				}else{
					throw new NoMatchError();
				}
			}
			return new DFSResult(root, nins, des, nins == S.size());
		}else{
			throw new NoMatchError();
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}

import java.io.*;
import java.util.*;

public class PQTree_test {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

	static PQNode[] collect(PQNode[] arr, int whatStatus) {
		int sz = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				sz++;
			}
		}

		PQNode[] ret = new PQNode[sz];
		int ptr = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				ret[ptr++] = v;
			}
		}

		return ret;
	}

	static PQNode makeNode(PQNode[] arr, int whatType) {
		if (arr.length == 0) {
			return null;
		}
		if (arr.length == 1) {
			return arr[0];
		}
		if (arr.length == 2) {
			whatType = PQNode.Q_NODE;
		}
		return new PQNode(whatType, arr);
	}

	static <T> void fullCopy(T[] src, T[] dest, int destPos) {
		System.arraycopy(src, 0, dest, destPos, src.length);
	}

	static PQNode[] appendFirst(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		ret[0] = v;
		fullCopy(arr, ret, 1);
		return ret;
	}

	static PQNode[] appendLast(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		fullCopy(arr, ret, 0);
		ret[arr.length] = v;
		return ret;
	}

	static PQNode[] concat(PQNode[] arr1, PQNode[] arr2) {
		PQNode[] ret = new PQNode[arr1.length + arr2.length];
		fullCopy(arr1, ret, 0);
		fullCopy(arr2, ret, arr1.length);
		return ret;
	}

	static <T> void reverse(T[] a) {
		for (int i = 0, j = a.length - 1; i < j; i++, j--) {
			T tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
		}
	}

	static class PQNode {
		static final int P_NODE = -1;
		static final int Q_NODE = -2;

		/**
		 * < 0 if P or Q node

		 * otherwise this node is leaf and type is number of element
		 */
		int type;
		PQNode[] child;

		public PQNode(int type, PQNode[] child) {
			this.type = type;
			this.child = child;
		}

		static final int EMPTY = 0;
		static final int FULL = 1;
		static final int PARTIAL = 2;
		static final int CONTAINS_ALL = 3;
		/**
		 * see above for possible values

		 * in case of partial, first children are in current query, then not
		 */
		int status;

		/**
		 * number of leafs from current query in this subtree
		 */
		int count;

		PQNode dfs(boolean[] b, int allQry) {

			if (type >= 0) {
				status = b[type] ? FULL : EMPTY;
				count = b[type] ? 1 : 0;
				return this;
			}

			count = 0;

			boolean allFull = true;
			boolean allEmpty = true;
			int cntPartial = 0;
			int[] idxPartial = new int[2];

			for (int i = 0; i < child.length; i++) {
				child[i] = child[i].dfs(b, allQry);
				if (child[i] == null) {
					return null;
				}
			}

			for (int i = 0; i < child.length; i++) {
				PQNode v = child[i];

				if (v.status == CONTAINS_ALL) {
					status = CONTAINS_ALL;
					return this;
				}
				allFull &= v.status == FULL;
				allEmpty &= v.status == EMPTY;
				if (v.status == PARTIAL) {
					if (cntPartial == 2) {
						return null;
					}
					idxPartial[cntPartial++] = i;
				}
				count += v.count;
			}

			boolean doesContainAll = count == allQry;

			if (allFull) {
				status = FULL;
				return this;
			}

			if (allEmpty) {
				status = EMPTY;
				return this;
			}

			if (cntPartial <= 1 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				PQNode fullAndPartial;
				if (cntPartial == 0) {
					fullAndPartial = fullNode;
				} else {
					PQNode[] arr = appendFirst(fullNode,
							child[idxPartial[0]].child);
					fullAndPartial = makeNode(arr, Q_NODE);
				}

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (cntPartial <= 1 && type == P_NODE && !doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode full = makeNode(fulls, P_NODE);
				if (full != null) {
					full.status = FULL;
				}
				PQNode empty = makeNode(emptys, P_NODE);
				if (empty != null) {
					empty.status = EMPTY;
				}

				PQNode ret;
				if (cntPartial == 1) {
					PQNode[] arr = appendFirst(full,
							appendLast(empty, child[idxPartial[0]].child));
					ret = makeNode(arr, Q_NODE);
				} else {
					ret = makeNode(new PQNode[] { full, empty }, Q_NODE);
				}
				ret.count = count;
				ret.status = PARTIAL;
				return ret;
			}

			if (cntPartial == 2 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				reverse(child[idxPartial[0]].child);

				PQNode[] tmp = appendLast(fullNode, child[idxPartial[0]].child);
				PQNode fullAndPartial = makeNode(
						concat(tmp, child[idxPartial[1]].child), Q_NODE);

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (type == Q_NODE) {
				int size = child.length;
				for (int i = 0; i < cntPartial; i++) {
					size += child[idxPartial[i]].child.length - 1;
				}

				PQNode[] arr = new PQNode[size];
				int ptr = 0;

				boolean firstPartial = true;
				for (int i = 0; i< child.length; i++) {
					PQNode v = child[i];
					if (v.status == PARTIAL) {

						boolean shouldRev;
						if (cntPartial == 1) {
							if (i == 0) {
								shouldRev = child[i + 1].status == FULL;
							} else {
								shouldRev = child[i - 1].status == EMPTY;
							}
						} else {
							shouldRev = firstPartial;
							firstPartial = !firstPartial;
						}

						if (shouldRev) {
							reverse(v.child);
						}

						for (PQNode u : v.child) {
							arr[ptr++] = u;
						}
					} else {
						arr[ptr++] = v;
					}
				}

				if (arr[arr.length - 1].status == FULL) {
					reverse(arr);
				}

				ptr = arr.length - 1;
				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}
				while (ptr >= 0 && arr[ptr].status == FULL) {
					ptr--;
				}

				if (ptr == -1) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.count = count;
					ret.status = doesContainAll ? CONTAINS_ALL : PARTIAL;
					return ret;
				}

				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}

				if (ptr == -1 && doesContainAll) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.status = CONTAINS_ALL;
					return ret;
				}
			}

			return null;
		}

		void genRepr(StringBuilder sb) {
			if (type >= 0) {
				sb.append(type + " ");
				return;
			}
			sb.append(type == P_NODE ? "[" : "(");
			for (PQNode v : child) {
				v.genRepr(sb);
			}
			sb.append(type == P_NODE ? "]" : ")");
		}

		void getOrder(List<Integer> ret) {
			if (type >= 0) {
				ret.add(type);
				return;
			}
			for (PQNode v : child) {
				v.getOrder(ret);
			}
		}
	}

	static class PQTree {
		/**
		 * null if there are no permutations
		 */
		PQNode root;
		int n;

		public PQTree(int n) {
			this.n = n;
			PQNode[] arr = new PQNode[n];
			for (int i = 0; i < n; i++) {
				arr[i] = new PQNode(i, null);
			}
			root = makeNode(arr, PQNode.P_NODE);
		}

		void update(boolean[] b) {
			if (root == null) {
				return;
			}
			int cnt = 0;
			for (boolean flag : b) {
				cnt += flag ? 1 : 0;
			}
			if (cnt <= 1 || cnt == b.length) {
//				System.err.println("skipped");
				return;
			}
			root = root.dfs(b, cnt);

//			System.err.println(this);
		}

		@Override
		public String toString() {
			if (root == null) {
				return "null";
			}
			StringBuilder sb = new StringBuilder();
			root.genRepr(sb);
			return sb.toString();
		}

		List<Integer> getOrder() {
			List<Integer> ret = new ArrayList<>(n);
			root.getOrder(ret);
			return ret;
		}
	}

	void submit() throws IOException {
//		PQTree tree = new PQTree(6);
//		tree.update(new boolean[] { true, false, false, false, true, false });
//		tree.update(new boolean[] { true, true, false, true, true, false });
//		tree.update(new boolean[] { false, true, true, false, false, true});
//		tree.update(new boolean[] { false, true, false, false, true, false});
//		tree.update(new boolean[] { false, false, false, true, false, false});
//		tree.update(new boolean[] { false, true, true, false, false, true});

		int n = nextInt();
		PQTree tree = new PQTree(n);
		char[][] f = new char[n][];
		for (int i = 0; i < n; i++) {
			f[i] = nextToken().toCharArray();
			boolean[] b = new boolean[n];
			for (int j = 0; j < n; j++) {
				b[j] = f[i][j] == '1';
			}
			tree.update(b);
		}

		if (tree.root == null) {
			out.println("NO");
			return;
		}

		out.println("YES");
		List<Integer> order = tree.getOrder();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				out.print(f[i][order.get(j)]);
			}
			out.println();
		}

	}

	static final Random rng = new Random();

	int[] genRandomPerm(int n) {
		int[] p = new int[n];
		for (int i = 0; i < n; i++) {
			int j = rng.nextInt(i + 1);
			p[i] = p[j];
			p[j] = i;
		}
		return p;
	}

	void oneTest(int n) {
		int[] p = genRandomPerm(n);
		char[][] f = new char[n][n];

		PQTree t = new PQTree(n);

		for (int i = 0; i < n; i++) {
			Arrays.fill(f[i], '0');
			int low = rng.nextInt(n);
			int high = rng.nextInt(n);
			if (low > high) {
				int tmp = low;
				low = high;
				high = tmp;
			}

			boolean[] b = new boolean[n];
			for (int j = low; j <= high; j++) {
				f[i][p[j]] = '1';
				b[p[j]] = true;
			}

			t.update(b);
		}

		if (t.root == null) {
			System.err.println(n);
			System.err.println(Arrays.toString(p));
			for (int i = 0; i < n; i++) {
				System.err.println(f[i]);
			}
			throw new AssertionError();
		}
	}

	void stress(int n) {
		for (int tst = 0; tst >= 0; tst++) {
			oneTest(n);
			System.err.println(tst);
		}
	}

	void test() {
		PQTree t = new PQTree(5);
		t.update(new boolean[]{false, false, true, true, false});
		t.update(new boolean[]{true, true, true, true, false});
		t.update(new boolean[]{true, true, true, false, true});
	}

	PQTree_test() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		submit();
//		stress(100);
//		test();
		out.close();
	}

	public static void main(String[] args) throws IOException {
		new PQTree_test();
	}

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
}

import java.util.InputMismatchException;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.IOException;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author George Marcus
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskE solver = new TaskE();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskE {
    char[][] A;
    int[] ans;
    ArrayList<Integer>[] B;
    int[] inGroup;

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        int N = in.nextInt();
        A = new char[N][];
        for (int i = 0; i < N; i++) {
            A[i] = in.nextString().toCharArray();
        }

        ans = new int[N + 1];
        B = new ArrayList[N];
        for (int i = 0; i < N; i++) {
            B[i] = new ArrayList<Integer>();
            for (int j = 0; j < N; j++) {
                if (A[i][j] == '1') {
                    B[i].add(j);
                }
            }
        }

        ArrayList<Integer> rows = new ArrayList<Integer>();
        ArrayList<Integer> cols = new ArrayList<Integer>();
        for (int i = 0; i < N; i++) {
            if (!B[i].isEmpty()) {
                rows.add(i);
            }
            cols.add(i);
        }

        inGroup = new int[N];
        if (go(rows, cols)) {
            if (ans[0] != N) {
                throw new RuntimeException();
            }

            out.println("YES");
            for (int i = 0; i < N; i++) {
                for (int j = 1; j <= N; j++) {
                    out.print(A[i][ans[j]]);
                }
                out.println();
            }
        }
        else {
            out.println("NO");
        }
    }

    private boolean go(ArrayList<Integer> rows, ArrayList<Integer> cols) {
        if (rows.isEmpty()) {
            for (int col : cols) {
                ans[++ans[0]] = col;
            }
            return true;
        }

        int pmax = 0;
        for (int i = 1; i < rows.size(); i++) {
            if (B[rows.get(i)].size() > B[rows.get(pmax)].size()) {
                pmax = i;
            }
        }
        int maxRow = rows.get(pmax);
        rows.remove(pmax);

        ArrayList<ArrayList<Integer>> groups = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> ones = new ArrayList<Integer>();
        ArrayList<Integer> zeros = new ArrayList<Integer>();
        split(maxRow, cols, ones, zeros);
        groups.add(ones);
        groups.add(zeros);

        if (rows.isEmpty()) {
            for (ArrayList<Integer> gcols : groups) {
                for (int gcol : gcols) {
                    ans[++ans[0]] = gcol;
                }
            }
            return true;
        }
        if (ones.isEmpty() || zeros.isEmpty()) {
            return go(rows, cols);
        }

        int p = -1;
        int special = groups.get(groups.size() - 1).size();
        while ((p = find(groups, rows)) != -1) {
            rows.remove((Integer) p);

            int state = 0;
            boolean maybe = false;
            ArrayList<ArrayList<Integer>> ngroups = new ArrayList<ArrayList<Integer>>();
            for (int i = 0; i < groups.size(); i++) {
                ArrayList<Integer> group = groups.get(i);
                ones = new ArrayList<Integer>();
                zeros = new ArrayList<Integer>();
                split(p, group, ones, zeros);

                if (state == 0) {
                    if (!zeros.isEmpty()) ngroups.add(zeros);
                    if (!ones.isEmpty()) {
                        ngroups.add(ones);
                        state = 1;
                    }
                }
                else if (state == 1) {
                    if (!ones.isEmpty()) ngroups.add(ones);
                    if (!zeros.isEmpty()) {
                        ngroups.add(zeros);
                        state = 2;
                    }
                }
                else { // 2
                    if (!zeros.isEmpty()) ngroups.add(zeros);
                    if (!ones.isEmpty()) {
                        if (i + 1 < groups.size() || special == 0) {
                            return false;
                        }
                        else {
                            maybe = true;
                        }
                    }
                }
                if (i == groups.size() - 1) {
                    special -= ones.size();
                }
            }

            if (maybe) {
                ngroups = new ArrayList<ArrayList<Integer>>();
                state = 0;
                for (int i = 0; i < groups.size(); i++) {
                    ArrayList<Integer> group = groups.get(i);
                    ones = new ArrayList<Integer>();
                    zeros = new ArrayList<Integer>();
                    split(p, group, ones, zeros);

                    if (i == groups.size() - 1) {
                        if (!ones.isEmpty()) ngroups.add(0, ones);
                        if (!zeros.isEmpty()) ngroups.add(zeros);
                        break;
                    }
                    if (!ones.isEmpty()) {
                        if (state == 1) return false;
                        ngroups.add(ones);
                    }
                    if (!zeros.isEmpty()) {
                        if (state == 0) state = 1;
                        ngroups.add(zeros);
                    }
                }
            }

            groups = ngroups;
        }

        ArrayList<Integer>[] groupRows = new ArrayList[groups.size()];
        for (int i = 0; i < groups.size(); i++) {
            groupRows[i] = new ArrayList<Integer>();
        }
        for (int r : rows) {
            int f = B[r].get(0);
            int g = inGroup[f];
            groupRows[g].add(r);
        }
        for (int i = 0; i < groups.size(); i++) {
            if (!go(groupRows[i], groups.get(i))) {
                return false;
            }
        }
        return true;
    }

    private int find(ArrayList<ArrayList<Integer>> groups, ArrayList<Integer> rows) {
        for (int i = 0; i < groups.size(); i++) {
            for (int col : groups.get(i)) {
                inGroup[col] = i;
            }
        }
        for (int r : rows) {
            for (int j = 1; j < B[r].size(); j++) {
                if (inGroup[ B[r].get(j - 1) ] != inGroup[ B[r].get(j) ]) {
                    return r;
                }
            }
        }
        return -1;
    }

    private void split(int row, ArrayList<Integer> cols, ArrayList<Integer> ones, ArrayList<Integer> zeros) {
        for (int col : cols) {
            if (A[row][col] == '1') {
                ones.add(col);
            }
            else {
                zeros.add(col);
            }
        }
    }
}

class InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar;
    private int numChars;

    public InputReader(InputStream stream) {
        this.stream = stream;
    }

    public int read() {
        if (numChars == -1)
            throw new InputMismatchException();
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar++];
    }

    public int nextInt() {
        return Integer.parseInt(nextString());
    }

    public String nextString() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        StringBuffer res = new StringBuffer();
        do {
            res.appendCodePoint(c);
            c = read();
        } while (!isSpaceChar(c));

        return res.toString();
    }

    private boolean isSpaceChar(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

}

import java.io.*;
import java.util.*;

public class PQTree_test {

	BufferedReader br;
	PrintWriter out;
	StringTokenizer st;
	boolean eof;

	static PQNode[] collect(PQNode[] arr, int whatStatus) {
		int sz = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				sz++;
			}
		}

		PQNode[] ret = new PQNode[sz];
		int ptr = 0;
		for (PQNode v : arr) {
			if (v.status == whatStatus) {
				ret[ptr++] = v;
			}
		}

		return ret;
	}

	static PQNode makeNode(PQNode[] arr, int whatType) {
		if (arr.length == 0) {
			return null;
		}
		if (arr.length == 1) {
			return arr[0];
		}
		if (arr.length == 2) {
			whatType = PQNode.Q_NODE;
		}
		return new PQNode(whatType, arr);
	}

	static <T> void fullCopy(T[] src, T[] dest, int destPos) {
		System.arraycopy(src, 0, dest, destPos, src.length);
	}

	static PQNode[] appendFirst(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		ret[0] = v;
		fullCopy(arr, ret, 1);
		return ret;
	}

	static PQNode[] appendLast(PQNode v, PQNode[] arr) {
		if (v == null) {
			return arr;
		}
		PQNode[] ret = new PQNode[arr.length + 1];
		fullCopy(arr, ret, 0);
		ret[arr.length] = v;
		return ret;
	}

	static PQNode[] concat(PQNode[] arr1, PQNode[] arr2) {
		PQNode[] ret = new PQNode[arr1.length + arr2.length];
		fullCopy(arr1, ret, 0);
		fullCopy(arr2, ret, arr1.length);
		return ret;
	}

	static <T> void reverse(T[] a) {
		for (int i = 0, j = a.length - 1; i < j; i++, j--) {
			T tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
		}
	}

	static class PQNode {
		static final int P_NODE = -1;
		static final int Q_NODE = -2;

		/**
		 * < 0 if P or Q node

		 * otherwise this node is leaf and type is number of element
		 */
		int type;
		PQNode[] child;

		public PQNode(int type, PQNode[] child) {
			this.type = type;
			this.child = child;
		}

		static final int EMPTY = 0;
		static final int FULL = 1;
		static final int PARTIAL = 2;
		static final int CONTAINS_ALL = 3;
		/**
		 * see above for possible values

		 * in case of partial, first children are in current query, then not
		 */
		int status;

		/**
		 * number of leafs from current query in this subtree
		 */
		int count;

		PQNode dfs(boolean[] b, int allQry) {

			if (type >= 0) {
				status = b[type] ? FULL : EMPTY;
				count = b[type] ? 1 : 0;
				return this;
			}

			count = 0;

			boolean allFull = true;
			boolean allEmpty = true;
			int cntPartial = 0;
			int[] idxPartial = new int[2];

			for (int i = 0; i < child.length; i++) {
				child[i] = child[i].dfs(b, allQry);
				if (child[i] == null) {
					return null;
				}
			}

			for (int i = 0; i < child.length; i++) {
				PQNode v = child[i];

				if (v.status == CONTAINS_ALL) {
					status = CONTAINS_ALL;
					return this;
				}
				allFull &= v.status == FULL;
				allEmpty &= v.status == EMPTY;
				if (v.status == PARTIAL) {
					if (cntPartial == 2) {
						return null;
					}
					idxPartial[cntPartial++] = i;
				}
				count += v.count;
			}

			boolean doesContainAll = count == allQry;

			if (allFull) {
				status = FULL;
				return this;
			}

			if (allEmpty) {
				status = EMPTY;
				return this;
			}

			if (cntPartial <= 1 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				PQNode fullAndPartial;
				if (cntPartial == 0) {
					fullAndPartial = fullNode;
				} else {
					PQNode[] arr = appendFirst(fullNode,
							child[idxPartial[0]].child);
					fullAndPartial = makeNode(arr, Q_NODE);
				}

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (cntPartial <= 1 && type == P_NODE && !doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode full = makeNode(fulls, P_NODE);
				PQNode empty = makeNode(emptys, P_NODE);

				PQNode ret;
				if (cntPartial == 1) {
					PQNode[] arr = appendFirst(full,
							appendLast(empty, child[idxPartial[0]].child));
					ret = makeNode(arr, Q_NODE);
				} else {
					ret = makeNode(new PQNode[] { full, empty }, Q_NODE);
				}
				ret.count = count;
				ret.status = PARTIAL;
				return ret;
			}

			if (cntPartial == 2 && type == P_NODE && doesContainAll) {
				PQNode[] fulls = collect(child, FULL);
				PQNode[] emptys = collect(child, EMPTY);

				PQNode fullNode = makeNode(fulls, P_NODE);

				reverse(child[idxPartial[0]].child);

				PQNode[] tmp = appendLast(fullNode, child[idxPartial[0]].child);
				PQNode fullAndPartial = makeNode(
						concat(tmp, child[idxPartial[1]].child), Q_NODE);

				PQNode[] arr = appendFirst(fullAndPartial, emptys);
				PQNode ret = makeNode(arr, P_NODE);
				ret.status = CONTAINS_ALL;
				return ret;
			}

			if (type == Q_NODE) {
				int size = child.length;
				for (int i = 0; i < cntPartial; i++) {
					size += child[idxPartial[i]].child.length - 1;
				}

				PQNode[] arr = new PQNode[size];
				int ptr = 0;

				boolean firstPartial = true;
				for (int i = 0; i< child.length; i++) {
					PQNode v = child[i];
					if (v.status == PARTIAL) {

						boolean shouldRev;
						if (cntPartial == 1) {
							if (i == 0) {
								shouldRev = child[i + 1].status == FULL;
							} else {
								shouldRev = child[i - 1].status == EMPTY;
							}
						} else {
							shouldRev = firstPartial;
							firstPartial = !firstPartial;
						}

						if (shouldRev) {
							reverse(v.child);
						}

						for (PQNode u : v.child) {
							arr[ptr++] = u;
						}
					} else {
						arr[ptr++] = v;
					}
				}

				if (arr[arr.length - 1].status == FULL) {
					reverse(arr);
				}

				ptr = arr.length - 1;
				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}
				while (ptr >= 0 && arr[ptr].status == FULL) {
					ptr--;
				}

				if (ptr == -1) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.count = count;
					ret.status = doesContainAll ? CONTAINS_ALL : PARTIAL;
					return ret;
				}

				while (ptr >= 0 && arr[ptr].status == EMPTY) {
					ptr--;
				}

				if (ptr == -1 && doesContainAll) {
					PQNode ret = makeNode(arr, Q_NODE);
					ret.status = CONTAINS_ALL;
					return ret;
				}
			}

			return null;
		}

		void genRepr(StringBuilder sb) {
			if (type >= 0) {
				sb.append(type + " ");
				return;
			}
			sb.append(type == P_NODE ? "[" : "(");
			for (PQNode v : child) {
				v.genRepr(sb);
			}
			sb.append(type == P_NODE ? "]" : ")");
		}

		void getOrder(List<Integer> ret) {
			if (type >= 0) {
				ret.add(type);
				return;
			}
			for (PQNode v : child) {
				v.getOrder(ret);
			}
		}
	}

	static class PQTree {
		/**
		 * null if there are no permutations
		 */
		PQNode root;
		int n;

		public PQTree(int n) {
			this.n = n;
			PQNode[] arr = new PQNode[n];
			for (int i = 0; i < n; i++) {
				arr[i] = new PQNode(i, null);
			}
			root = makeNode(arr, PQNode.P_NODE);
		}

		void update(boolean[] b) {
			if (root == null) {
				return;
			}
			int cnt = 0;
			for (boolean flag : b) {
				cnt += flag ? 1 : 0;
			}
			if (cnt <= 1 || cnt == b.length) {
				return;
			}
			root = root.dfs(b, cnt);

//			System.err.println(this);

		}

		@Override
		public String toString() {
			if (root == null) {
				return "null";
			}
			StringBuilder sb = new StringBuilder();
			root.genRepr(sb);
			return sb.toString();
		}

		List<Integer> getOrder() {
			List<Integer> ret = new ArrayList<>(n);
			root.getOrder(ret);
			return ret;
		}
	}

	void solve() throws IOException {
//		PQTree tree = new PQTree(6);
//		tree.update(new boolean[] { true, false, false, false, true, false });
//		tree.update(new boolean[] { true, true, false, true, true, false });
//		tree.update(new boolean[] { false, true, true, false, false, true});
//		tree.update(new boolean[] { false, true, false, false, true, false});
//		tree.update(new boolean[] { false, false, false, true, false, false});
//		tree.update(new boolean[] { false, true, true, false, false, true});

		int n = nextInt();
		PQTree tree = new PQTree(n);
		char[][] f = new char[n][];
		for (int i = 0; i < n; i++) {
			f[i] = nextToken().toCharArray();
			boolean[] b = new boolean[n];
			for (int j = 0; j < n; j++) {
				b[j] = f[i][j] == '1';
			}
			tree.update(b);
		}

		if (tree.root == null) {
			out.println("NO");
			return;
		}

		out.println("YES");
		List<Integer> order = tree.getOrder();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				out.print(f[i][order.get(j)]);
			}
			out.println();
		}

	}

	PQTree_test() throws IOException {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
	}

	public static void main(String[] args) throws IOException {
		new PQTree_test();
	}

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return null;
			}
		}
		return st.nextToken();
	}

	String nextString() {
		try {
			return br.readLine();
		} catch (IOException e) {
			eof = true;
			return null;
		}
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}
}

import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author George Marcus
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskE solver = new TaskE();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskE {
    char[][] A;
    int[] ans;
    ArrayList<Integer>[] B;
    int[] inGroup;

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        int N = in.nextInt();
        A = new char[N][];
        for (int i = 0; i < N; i++) {
            A[i] = in.nextString().toCharArray();
        }

        ans = new int[N + 1];
        B = new ArrayList[N];
        for (int i = 0; i < N; i++) {
            B[i] = new ArrayList<Integer>();
            for (int j = 0; j < N; j++) {
                if (A[i][j] == '1') {
                    B[i].add(j);
                }
            }
        }

        ArrayList<Integer> rows = new ArrayList<Integer>();
        ArrayList<Integer> cols = new ArrayList<Integer>();
        for (int i = 0; i < N; i++) {
            if (!B[i].isEmpty()) {
                rows.add(i);
            }
            cols.add(i);
        }

        inGroup = new int[N];
        if (go(rows, cols)) {
            out.println("YES");
            for (int i = 0; i < N; i++) {
                for (int j = 1; j <= N; j++) {
                    out.print(A[i][ans[j]]);
                }
                out.println();
            }
        }
        else {
            out.println("NO");
        }
    }

    private boolean go(ArrayList<Integer> rows, ArrayList<Integer> cols) {
        if (rows.isEmpty()) {
            for (int col : cols) {
                ans[++ans[0]] = col;
            }
            return true;
        }

        int pmax = 0;
        for (int i = 1; i < rows.size(); i++) {
            if (B[rows.get(i)].size() > B[rows.get(pmax)].size()) {
                pmax = i;
            }
        }
        rows.remove(pmax);

        ArrayList<ArrayList<Integer>> groups = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> ones = new ArrayList<Integer>();
        ArrayList<Integer> zeros = new ArrayList<Integer>();
        split(pmax, cols, ones, zeros);
        groups.add(ones);
        groups.add(zeros);

        if (rows.isEmpty()) {
            for (ArrayList<Integer> gcols : groups) {
                for (int gcol : gcols) {
                    ans[++ans[0]] = gcol;
                }
            }
            return true;
        }
        if (ones.isEmpty() || zeros.isEmpty()) {
            return go(rows, cols);
        }

        int p = -1;
        int special = groups.get(groups.size() - 1).size();
        while ((p = find(groups, rows)) != -1) {
            rows.remove((Integer) p);

            int state = 0;
            boolean maybe = false;
            ArrayList<ArrayList<Integer>> ngroups = new ArrayList<ArrayList<Integer>>();
            for (int i = 0; i < groups.size(); i++) {
                ArrayList<Integer> group = groups.get(i);
                ones = new ArrayList<Integer>();
                zeros = new ArrayList<Integer>();
                split(p, group, ones, zeros);

                if (state == 0) {
                    if (!zeros.isEmpty()) ngroups.add(zeros);
                    if (!ones.isEmpty()) {
                        ngroups.add(ones);
                        state = 1;
                    }
                }
                else if (state == 1) {
                    if (!ones.isEmpty()) ngroups.add(ones);
                    if (!zeros.isEmpty()) {
                        ngroups.add(zeros);
                        state = 2;
                    }
                }
                else if (state == 2) {
                    if (!zeros.isEmpty()) ngroups.add(zeros);
                    if (!ones.isEmpty()) {
                        if (i + 1 < groups.size() || special == 0) {
                            return false;
                        }
                        else {
                            maybe = true;
                        }
                    }
                }
                if (i == groups.size() - 1) {
                    special -= ones.size();
                }
            }

            if (maybe) {
                ngroups = new ArrayList<ArrayList<Integer>>();
                state = 0;
                for (int i = 0; i < groups.size(); i++) {
                    ArrayList<Integer> group = groups.get(i);
                    ones = new ArrayList<Integer>();
                    zeros = new ArrayList<Integer>();
                    split(p, group, ones, zeros);

                    if (i == groups.size() - 1) {
                        if (!ones.isEmpty()) ngroups.add(0, ones);
                        if (!zeros.isEmpty()) ngroups.add(zeros);
                        continue;
                    }
                    if (!ones.isEmpty()) {
                        if (state == 1) return false;
                        ngroups.add(ones);
                    }
                    if (!zeros.isEmpty()) {
                        if (state == 0) state = 1;
                        ngroups.add(zeros);
                    }
                }
            }

            groups = ngroups;
        }

        ArrayList<Integer>[] groupRows = new ArrayList[groups.size()];
        for (int i = 0; i < groups.size(); i++) {
            groupRows[i] = new ArrayList<Integer>();
        }
        for (int r : rows) {
            int f = B[r].get(0);
            int g = inGroup[f];
            groupRows[g].add(r);
        }
        for (int i = 0; i < groups.size(); i++) {
            ArrayList<Integer> group = groups.get(i);
            if (!go(groupRows[i], group)) {
                return false;
            }
        }
        return true;
    }

    private int find(ArrayList<ArrayList<Integer>> groups, ArrayList<Integer> rows) {
        for (int i = 0; i < groups.size(); i++) {
            ArrayList<Integer> group = groups.get(i);
            for (int col : group) {
                inGroup[col] = i;
            }
        }
        for (int r : rows) {
            for (int j = 1; j < B[r].size(); j++) {
                if (inGroup[ B[r].get(j - 1) ] != inGroup[ B[r].get(j) ]) {
                    return r;
                }
            }
        }
        return -1;
    }

    private void split(int row, ArrayList<Integer> cols, ArrayList<Integer> ones, ArrayList<Integer> zeros) {
        for (int col : cols) {
            if (A[row][col] == '1') {
                ones.add(col);
            }
            else {
                zeros.add(col);
            }
        }
    }
}

class InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar;
    private int numChars;

    public InputReader(InputStream stream) {
        this.stream = stream;
    }

    public int read() {
        if (numChars == -1)
            throw new InputMismatchException();
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar++];
    }

    public int nextInt() {
        return Integer.parseInt(nextString());
    }

    public String nextString() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        StringBuffer res = new StringBuffer();
        do {
            res.appendCodePoint(c);
            c = read();
        } while (!isSpaceChar(c));

        return res.toString();
    }

    private boolean isSpaceChar(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

}