#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 1005

struct Edge{
	Edge(int arg_to,int arg_capacity,int arg_rev_index){
		to = arg_to;
		capacity = arg_capacity;
		rev_index = arg_rev_index;
	}
	int to,capacity,rev_index;
};

int N;
int V;
int rank_index[NUM],component_index[NUM],rev_component[NUM];
vector<Edge> G[NUM];
int dist[NUM];
int cheked_index[NUM];

void add_edge(int from,int to,int capacity){
	G[from].push_back(Edge(to,capacity,G[to].size()));
	G[to].push_back(Edge(from,0,G[from].size()-1));
}

void delete_edge(int from,int index){

	//ノーマル辺を消す
	G[from][index].capacity = 0;
	int rev_from = G[from][index].to;

	//逆辺を消す
	int left = 0,right = G[rev_from].size()-1,mid = (left+right)/2;

	while(left <= right){

		if(G[rev_from][mid].to == from){

			G[rev_from][mid].capacity = 0;
			return;

		}else if(G[rev_from][mid].to > from){

			right = mid-1;

		}else{
			left = mid+1;
		}
		mid = (left+right)/2;
	}
}

//sourceからの最短距離をBFSで計算する
void bfs(int source){
	for(int i = 0; i < V; i++)dist[i] = -1;
	queue<int> Q;
	dist[source] = 0;
	Q.push(source);

	while(!Q.empty()){
		int node_id = Q.front();
		Q.pop();
		for(int i = 0; i < G[node_id].size(); i++){
			Edge &e = G[node_id][i];
			if(e.capacity > 0 && dist[e.to] < 0){ //辺の容量が正で、かつエッジの行先に未訪問の場合
				dist[e.to] = dist[node_id]+1;
				Q.push(e.to);
			}
		}
	}
}

//増加パスをDFSで探す
int dfs(int node_id,int sink,int flow){
	if(node_id == sink)return flow; //終点についたらflowをreturn

	for(int &i = cheked_index[node_id]; i < G[node_id].size(); i++){ //node_idから出ているエッジを調査
		Edge &e = G[node_id][i];
		if(e.capacity > 0 && dist[node_id] < dist[e.to]){ //流せる余裕があり、かつsourceからの距離が増加する方法である場合
			int tmp_flow = dfs(e.to,sink,min(flow,e.capacity)); //流せるだけ流す
			if(tmp_flow > 0){ //流せた場合
				e.capacity -= tmp_flow; //流した分、エッジの容量を削減する
				G[e.to][e.rev_index].capacity += tmp_flow; //逆辺の容量を、流した分だけ増加させる
				return tmp_flow;
			}
		}
	}
	return 0;
}


//sourceからsinkへの最大流を求める
int max_flow(int source,int sink){ //source:始点 sink:終点
	int flow = 0,add;
	while(true){ //増加パスが存在する限り、流量を追加し続ける
		bfs(source);
		if(dist[sink] < 0)break; //sourceからsinkへと辿り着く残余グラフがない、つまり増加パスが無くなった場合、break
		for(int i = 0; i < V; i++)cheked_index[i] = 0;
		while((add = dfs(source,sink,BIG_NUM)) > 0){ //増加パスが見つかる間、加算
			flow += add;
		}
	}
	return flow;
}

bool find_a_path(int source,int sink){ //sourceからsinkへの増加パスがあるか調べる

	bfs(source);

	if(dist[sink] < 0){
		return false;
	}

	for(int i = 0; i < V; i++)cheked_index[i] = 0;

	return dfs(source,sink,1) == 1;
}

int main(){

	scanf("%d",&N);

	int source = 0,sink = 1;
	int index = 2;

	//上からの順番ノードのインデックス
	for(int i = 0; i <= N-2; i++){
		//★0オリジンにおいて(N-2)→(N-1)が最後の移動なので、iはN-2までで良い
		rank_index[i] = index++;
		add_edge(source,rank_index[i],1); //sourceから
	}

	//2部マッチング用の、部品ノードのインデックス
	for(int i = 0; i <= N-2; i++){

		component_index[i] = index++;
		rev_component[component_index[i]] = i; //逆引き表
		add_edge(component_index[i],sink,1);
	}

	V = index;

	int tmp;

	for(int i = 0; i <= N-2; i++){ //部品のループ
		for(int k = 0; k <= N-2; k++){ //棒のループ

			scanf("%d",&tmp);
			if(tmp == 1){ //位置kから、k+1に移動できるなら、順番ノードと部品を紐づける
				add_edge(rank_index[k],component_index[i],1);
			}
		}
	}

	if(max_flow(source,sink) < N-1){ //そもそも0→N-1に移動できないなら不可

		printf("no\n");
		return 0;
	}

	printf("yes\n");

	for(int rank = rank_index[0]; rank <= rank_index[N-2]; rank++){
	//for(int rank = rank_index[0]; rank <= rank_index[0]; rank++){
		//番号の大きい部品から、降順に見ていく
		for(int i = G[rank].size()-1; i >= 0; i--){

			if(G[rank][i].capacity == 1){ //エッジに流れていない場合

				delete_edge(rank,i); //流れないように、辺を論理削除

			}else{ //エッジに流れている場合

				//★残余グラフ上で別の経路がないか試す★
				if(find_a_path(rank,G[rank][i].to)){

					/*
					 * ★source→rank,
					 * G[rank][i].to→sinkの状況は変わらずに、
					 * rank→G[rank][i].toの経路が変わっただけなので、
					 * エッジiを論理削除すれば流量は変わらない
					 *
					 * */
					delete_edge(rank,i); //より小さい番号の部品とマッチできるので、辺を論理削除

				}else{ //流せない:辺確定

					printf("%d\n",rev_component[G[rank][i].to]+1);
					break;
				}
			}
		}
	}

	return 0;
}

