#include <bits/stdc++.h>
#define ed "\n"
#define fi first
#define se second
#define SZ size()
#define ll long long
#define V(a) vector <a>
#define P pair <int,int>
#define PB(a) push_back(a)
#define MK(a,b) make_pair(a,b)
#define all(a) a.begin(),a.end()
#define each(a,b) for(auto (a):(b))
#define MSET(a,b) memset((a),(b),sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rep2(i,a,b) for(int i=(a);i>=(b);i--)
#define debug(x) cout << "debug:" << x << endl;
#define close ios::sync_with_stdio(false),cin.tie(NULL);
using namespace std;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; }
ll lcm(ll a,ll b){ return a*b/gcd(a,b); }
ll ksm(ll a,ll b,ll mod){ll ans=1;while(b){if(b&1)ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return (ans)%mod;}
template <typename _tp> inline _tp read(_tp&x){
char ch=getchar(),sgn=0;x=0;
while(ch^'-'&&!isdigit(ch))ch=getchar();if(ch=='-')ch=getchar(),sgn=1;
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();if(sgn)x=-x;return x;
}
//head
const int maxn = 1005;
const int maxnode = maxn*maxn;
struct DLX{
int n,m;//矩阵大小
//上,下,左,右,列,行
int U[maxnode],D[maxnode],L[maxnode],R[maxnode],col[maxnode],row[maxnode];
int Head[maxn];//每一行的头节点
int ansed,ans[maxn],cnt;//选了几行,记录选择的行,总共多少个节点
//初始化
void init(int n,int m){
this->n = n; this->m = m;
//第0行,每一列的头节点
rep(i,0,m){
U[i] = i; D[i] = i;
L[i] = i-1; R[i] = i+1;
col[i] = i; row[i] = 0;
}
L[0] = m; R[m] = 0; cnt = m;
MSET(Head,-1); MSET(ans,0);
return ;
}
//添加节点
void push(int x,int y){
//模拟十字链表
D[++cnt] = D[y]; U[cnt] = y;
U[D[y]] = cnt; D[y] = cnt;
row[cnt] = x; col[cnt] = y;
if(Head[x] < 0){//该行没有元素,即当前元素是行首元素
Head[x] = cnt;
R[cnt] = cnt; L[cnt] = cnt;
}
else{
L[cnt] = Head[x]; R[cnt] = R[Head[x]];
L[R[Head[x]]] = cnt; R[Head[x]] = cnt;
}
}
//删除当前列为1的那些行
void del(int y){
R[L[y]] = R[y]; L[R[y]] = L[y];
for(int i = D[y];i != y;i = D[i])
for(int j = R[i];j != i;j = R[j])
D[U[j]] = D[j], U[D[j]] = U[j];
return ;
}
//回溯,将之前删除的节点连接回来
void reback(int y){
for(int i = U[y];i != y;i = U[i])
for(int j = L[i];j != i;j = L[j])
D[U[j]] = j, U[D[j]] = j;
R[L[y]] = y; L[R[y]] = y;
return ;
}
//递归进行跳跃操作
bool dancing(int dep){
if(!R[0]){//矩阵空了,结束
ansed = dep;
return true;
}
int c = R[0];
del(c);
for(int i = D[c];i != c;i = D[i]){
ans[dep] = row[i];
for(int j = R[i];j != i;j = R[j])
del(col[j]);
if(dancing(dep+1)) return true;
for(int j = L[i];j != i;j = L[j])
reback(col[j]);
}
return false;
}
}dlx;
int main(){
int n,m;cin >> n >> m;
dlx.init(n,m);
rep(i,1,n) rep(j,1,m){
int x;cin >> x;
if(x) dlx.push(i,j);
}
if(!dlx.dancing(0)) cout << "NO" << ed;
else{
rep(i,0,dlx.ansed-1) cout << dlx.ans[i] << " ";
cout << ed;
}
}