//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;
    }

}