/* 2019.5.1
support c++11
g++ -O2 -std=gnu++17 -Wall -Wno-sign-compare eg.cpp -o eg
https://gist.github.com/Haozun/ad7520ee9f3468b19b3618bc12942adf
*/
/*
warning: no functional programming like accumulate
*/
#pragma GCC optimize ("O3")
using namespace std;
#include <iostream>
#include <iomanip> //cout precision
#include <cassert>

#include <set>
// #include <map>
#include <unordered_map>
#include <unordered_set>
#include <stack>
#include <vector>
#include <queue>
#include <complex>
#include <bitset>
//memset, memory handle, memcmp, strcmp
#include <cstring> 

#include <cmath>
#include <numeric>
#include <algorithm>
// const 
    #define mod 1000000007
//type abbr
    #define ll long long
    #define pii pair<int,int>
    #define vi vector<int>
//abbr
    #define fi first
    #define se second
    
    #define all(x) begin(x),end(x)
    #define rall(x) rbegin(x),rend(x)
//func abbr
    #define between(x,a,b) ((x-a)*(x-b)<=0) //between(2,10,0) section [0,10]
    #define maxn(x) const int maxn=x+10
    #define append push_back
    #define Mem(x) memset(x,0,sizeof(x)) //init array
    #define mineq(x,a) if(a<x) x=a
    #define maxeq(x,a) if(a>x) x=a
    #define pow2(x) pow(2,x)
    #define lowbit(x) ((x)&(-x))
    #define isqrt(x) static_cast<int>(sqrt(x))
    #if __cplusplus <= 201703L
        #define gcd __gcd
        #define lcm(x,y) x/gcd(x,y)*y
    #endif
    #if __cplusplus <= 202003L
        #define ceil2(x) pow2(ceil(log2(x)))
        #define floor2(x) pow2(floor(log2(x)))
    #endif
    //len->size
        #if __cplusplus >= 201703L
            #define len(x) size(x)
        #else
            #define len(x) (x.size())
        #endif
    //pow->pow(a,b,mod) # Fast Power Algo
        inline ll pow(ll a,ll b) 
        {
            a%=mod;
            ll res=1;
            while(b){if(b&1) res=res*a%mod;a=a*a%mod;b>>=1;}
            return res;
        }	 
    //number theory
        inline int inv(int a,int b=mod-2){
            int ans=1;
            for(;b;b>>=1){
                if(b&1) ans=1ll*ans*a%mod;
                a=1ll*a*a%mod;
            }
            return ans;
        }

    
/* special */
    #define GET_MACRO(_0,_1,_2,_3,_N,...) _N
//give class method a alias
    #define FUNCTIONAMEQ(highLevelF, lowLevelF) \
    template<typename... Args> \
    inline auto highLevelF(Args&&... args) -> decltype(lowLevelF(forward<Args>(args)...)) \
    {return lowLevelF(forward<Args>(args)...);}

// cpp like for_each(begin(s),end(s),[](int&n){})
    #define for_iter(i, s) for(auto i=begin(s);i!=end(s);i++)
    #define for_iter_n(i, s, n) for(auto i=begin(s),_6=next(begin(s),n);i!=_6;++i)


//dict->unordered_map
    #define dict unordered_map
//type->typeindex
    #define isinstance(a,b) (typeid(a)==typeid(b)) //isinstance->typeid
    #include <typeindex>
    #define type(x) (type_map[typeid(x)]) //can't use with multiple comma
    dict<std::type_index,std::string> type_map;
//range->rep
    #define rep(...)  GET_MACRO(__VA_ARGS__,rep4,rep3,rep2,rep1)(__VA_ARGS__)
    #define rep4(i,a,b,c) for(int i=(a),_5=(b),_4=(c);_4*(i-_5)<0;i+=_4) //abandoned
    #define rep3(i,a,b) for(int i=(a),_5=(b);i<_5;++i)
    #define rep2(i,a) rep3(i,0,a)
    #define rep1(a) rep2(_,a)


// str
    //operator 
        // += int ,* int
    #define str string
    str operator*(const str& s, int rhs) {
        if(rhs==1){return s;}
        else{
            str s2(s);
            rep(rhs-1) s2+=(s);
            return s2;
        }
    }
    void operator+=(str&l, int r){
        if(r<=9){l.append(r+48);return;}
        else{
            int digits=pow(10,int(log10(r)));
            while(digits){
                int quotient=r/digits;
                l.append(quotient+48);
                r-=quotient*digits;
                digits/=10;
            }
        }
    }
/* algorithm boost*/
    //import bisect
        struct Bisect{
            template<class V,class T, class C=decltype(less<T>())>
            inline void insort_right(V& arr, const T& val, C comp=less<T>())
            {arr.insert(upper_bound(all(arr),val,comp),val);}
            template<class V,class T, class C=decltype(less<T>())>
            inline void insort_left(V& arr, const T& val, C comp=less<T>())
            {arr.insert(lower_bound(all(arr),val,comp),val);}
            template<class V,class T, class C=decltype(less<T>())>
            inline int bisect_right(const V& arr, const T& val, C comp=less<T>())
            {return distance(begin(arr),upper_bound(all(arr),val,comp));}
            template<class V,class T, class C=decltype(less<T>())>
            inline int bisect_left(const V& arr, const T& val, C comp=less<T>())
            {return distance(begin(arr),lower_bound(all(arr),val,comp));}
            FUNCTIONAMEQ(insort,insort_right)
            FUNCTIONAMEQ(bisect,bisect_right)
        };Bisect bisect= Bisect(); // use bisect.bisect(vi{1,2,3},2)
        
/* data structure*/
    // two dimension point
        // complex<int> is unspecified, try after delete
        template <class T >
        struct P2 : public complex<T>
        {
            using complex<T>::complex;
            P2(const complex<T> &rhs):complex<T>(rhs){}
            
            friend bool operator<(const P2 &lhs, const P2 &rhs){
                //for binary search
                return lhs.real()==rhs.real()?lhs.imag()<rhs.imag():lhs.real()<rhs.real();
            }
            using complex<T>::real;FUNCTIONAMEQ(x,real)
            inline void x(T val){*this=P2(val,this->imag());}
            using complex<T>::imag;FUNCTIONAMEQ(y,imag)
            inline void y(T val){*this=P2(this->real(),val);}
        };
    //heapq->heapq # iterable priority_queue; ordered list 
        template<class T, class C = vector<T>, class P = less<typename C::value_type> >
        struct heapq :std::priority_queue<T,C,P> {
            using priority_queue<T,C,P>::priority_queue;
            typename C::iterator begin() { return std::priority_queue<T, C, P>::c.begin(); }
            typename C::iterator end() { return std::priority_queue<T, C, P>::c.end(); }
        };

    /* 1d math vector operator
        vector v X const c
        v+v ; v+c ; v*c ; v*v ; and *= ,+= 
    */
        template<class T>
        vector<T> operator+(const vector<T>& l,const vector<T>& r){
            vector<T> res(l);
            rep(i,len(r)) res[i]+=r[i];
            return res;
        }
        template<class T,class R>
        vector<T> operator+(const vector<T>& l,const R& r){
            vector<T> res(l);
            rep(i,len(res)) res[i]+=r;
            return res;
        }
        template<class T>
        vector<T> operator*(const vector<T>& l,const vector<T>& r){
            vector<T> res(l);
            rep(i,len(r)) res[i]*=r[i];
            return res;
        }
        template<class T,class R>
        vector<T> operator*(const vector<T>& l,const R& r){
            vector<T> res(l);
            rep(i,len(res)) res[i]*=r;
            return res;
        }

        template<class T>
        void operator+=(vector<T>& res,const vector<T>& r)
        {rep(i,len(r)) res[i]+=r[i];}
        template<class T,class R>
        void operator+=(vector<T>& res,const R& r)
        {rep(i,len(res)) res[i]+=r;}
        template<class T>
        void operator*=(vector<T>& res,const vector<T>& r)
        {rep(i,len(r)) res[i]*=r[i];}
        template<class T,class R>
        void operator*=(vector<T>& res,const R& r)
        {rep(i,len(res)) res[i]*=r;}
//print->D,Da,Dv,print
    //default sep=' ',end='\n'
    inline void print(){cout<<'\n';}
    template<class T>
    inline void print(const T&h){cout<<h<<'\n';}
    template<class T,class... U>
    inline void print(const T& h, const U&... t){cout<<h<<' ';print(t...);}

/* input */
    template<class T>
    inline void in(T& h){cin>>h;}
    template<class T,class... U>
    inline void in(T& h, U&... t){cin>>h;in(t...);}
//pre set
    int __mystery = []() {
        /* io accelerater */
        ios::sync_with_stdio(0); cin.tie(NULL);
        /* type */
        type_map[typeid(int)]="int";
        type_map[typeid(float)]="float";
        type_map[typeid(ll)]="long long";
        type_map[typeid(double)]="double";
        type_map[typeid(pii)]="pair<int,int>";
        type_map[typeid(string)]="str";
        type_map[typeid(char)]="char";
        type_map[typeid(vi)]="vector<int>";
        type_map[typeid(set<int>)]="set<int>";
        type_map[typeid(vector<str>)]="vector<str>";
        type_map[typeid(dict<int,int>)]="dict<int,int>";
        return 42;
    }();



/* debug online judge */
#ifndef ONLINE_JUDGE
    //python style with # operator
    //print c++ stl container and c array with constant array size;
        template<class T>
        inline void D1(const T& x, str sep=", "){
            if(type(x)=="str") cout<<'"'<<x<<'"'<<sep;
            else if(type(x)=="char") cout<<'\''<<x<<'\''<<sep;
            else cout<<x<<sep;
        }
        #define Dv(...)  {cout<<#__VA_ARGS__<<"\t{";GET_MACRO(__VA_ARGS__,X,Dvec2,Dvec1,Ds)(__VA_ARGS__);cout<<"}\n";}
            #define Ds(...) for(const auto &__e : __VA_ARGS__ ) D1(__e); // use ... for initializer_list<>
            #define Dvec1(x,fir) {for_iter_n(_7,x,fir) D1(*_7);}
            #define Dvec2(x,fir,sec) {for(auto _9=begin(x),_6=next(_9,sec),_7=next(_9,fir);_7!=_6;_7++) D1(*_7);}
    //print single element, arbitary args
        #define D(...) {cout<<#__VA_ARGS__<<'\t';Dout(__VA_ARGS__);cout<<'\n';};
            inline void Dout(){cout<<'\n';}
            template<class T>
            inline void Dout(const T& h){D1(h,"");}
            template<class T,class... U>
            inline void Dout(const T& h,const U&... t){D1(h);Dout(t...);}
    // special additional print function 
    
        #define Da(...)  {cout<<#__VA_ARGS__<<"\t{";GET_MACRO(__VA_ARGS__,X,Darr2,Darr1,Dmap)(__VA_ARGS__);cout<<"}\n";}
            //variable size c array
            #define Darr1(x,s)  {rep(__j,s) D1(x[__j]);}
            #define Darr2(x,s,e)  {rep(__j,s,e) D1(x[__j]);}
            // map
            #define Dmap(mp) for(auto const& p:mp){D1(mp.fi,": ");D1(mp.se);}
        #define D2(...)  {cout<<#__VA_ARGS__<<"\n{\n";GET_MACRO(__VA_ARGS__,X,Da2,Dv2,Ds2)(__VA_ARGS__);cout<<"}\n";}
            #define Ds2(x) for(auto const& e:x) {cout<<"    {";Ds(e); cout<<"},\n";}
            #define Dv2(x,fir) for_iter_n(_8,x,fir) {cout<<"    {";Ds(*_8); cout<<"},\n";}
            #define Da2(x,r,c) rep(__i,r) {cout<<"    {";Darr1(x[__i],c);cout<<"},\n";}

#endif // ONLINE_JUDGE1

int H,W;
maxn(1000);
int col[maxn][maxn];
char t;
struct poi
{
    int x,y,c;
};
int posx[4]={0,0,1,-1};
int posy[4]={1,-1,0,0};
int main(){
    in(H,W);
    queue<poi> q;
    rep(i,H)rep(j,W){
       in(t);if(t=='#') {
           col[i][j]=1;
           q.push(poi{i,j,0});
       }else{
           col[i][j]=0;
       }
    }
    poi now,nxt;

    while(!q.empty()){
        now = q.front();q.pop();
        
        rep(i,4){
            nxt = now;
            nxt.x=now.x+posx[i];
            nxt.y=now.y+posy[i];
            nxt.c++;
            if(0<=nxt.x and nxt.x<H and 0<=nxt.y and nxt.y<W and col[nxt.x][nxt.y]==0){
                col[nxt.x][nxt.y]=1;
                q.push(nxt);
            }
        }
    }
    print(now.c);
}

Measured memory_bytes: 16272