// Slower C++ solution:
#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

#include <queue>

struct Node{

	int x,y;

	Node(int a,int b){

		x = a;

		y = b;

	}

	Node(){;}

};

 

queue<Node> q;

int N,M;

int xx[] = {0,0,0,1,-1};

int yy[] = {0,1,-1,0,0};

char str[1010][1010];

int F[1010][1010] = {0};

int main(){

	memset(F,0x3f,sizeof F);

	scanf("%d%d",&N,&M);

	for(int i = 1;i <= N;i++)scanf("%s",str[i]+1);

	for(int i = 1;i <= N;i++){

		for(int j = 1;j <= M;j++){

			if(str[i][j] == '#'){

				F[i][j] = 0;

				q.push(Node(i,j));

			}

		}

	}

	while(!q.empty()){

		Node D= q.front();

		q.pop();

		for(int i = 1;i <= 4;i++){

			int x = D.x + xx[i],y = D.y + yy[i];

			if(x < 1 || y < 1 || x > N || y > M)continue;

			if(F[x][y] > F[D.x][D.y] + 1){

				F[x][y] = F[D.x][D.y] + 1;

				q.push(Node(x,y));

			}

		}

	}

	int ans = 0;

	for(int i = 1;i <= N;i++){

		for(int j = 1;j <= M;j++){

			ans = max(ans,F[i][j]);

		}

	}

	printf("%d\n",ans);

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 4.847089369083252x):
/**

    OJ :

    Program Code :

    Md. Mujahedul Azad (Turin)

    Hajee Mohammad Danesh Science & Technology University

**/



#include <map>

#include <set>

#include <queue>

#include <stack>

#include <cctype>

#include <cstdio>

#include <math.h>

#include <string>

#include <vector>

#include <cassert>

#include <climits>

#include <cstdlib>

#include <cstring>

#include <iomanip>

#include <sstream>

#include <utility>

#include <iostream>

#include <iterator>

#include <algorithm>

/// #include<bits/stdc++.h>

using namespace std;



#define ff              first

#define se              second

#define nl              << '\n'

#define gf              << ' ' <<

#define pb              push_back

#define pi              2*acos(0.0)

#define sq(a)           ((a) * (a))

#define Sort(a)         sort(all(a))

#define sz(x)           (int)x.size()

#define fillAra(a,n,v)  fill(a, a+n, v)

#define fillVec(a, v)   fill(all(a), v)

#define btz(a)          __builtin_ctz(a)

#define all(v)          v.begin(),v.end()

#define max3(a,b,c)     max(a, max(b, c))

#define min3(a,b,c)     min(a, min(b, c))

#define abs(x)          (((x)<0)?-(x):(x))

#define parity(a)       __builtin_parity(a)

#define maxall(v)       *max_element(all(v))

#define minall(v)       *min_element(all(v))

#define cinIg           cin.sync(); cin.get()

#define countOne(a)     __builtin_popcount(a)

#define mem(a,v)        memset(a, v, sizeof(a))

#define RSort(a)        Sort(a), reverse(all(a))

#define precision(x)    cout << setprecision(x) << fixed

#define un(a)           Sort(a), (a).erase(unique(all(a)),a.end())

#define FasterIO        ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TestCases       int cases, tc; sfi(tc); for(cases=1; cases<=tc; cases++)

#define TestCasespp     int cases, tc; cin>>tc; for(cases=1; cases<=tc; cases++)

#define common(a,b)     Sort(a), Sort(b), a.erase(set_intersection(all(a), all(b), a.begin()), a.end())

#define uncommon(a,b)   Sort(a), Sort(b), a.erase(set_symmetric_difference(all(a), all(b), a.begin()), a.end())



/**------- ShortCuts----------*/

typedef long long             ll;

typedef unsigned long long    ull;

typedef double                db;

typedef long double           ldb;

typedef pair<int, int>        pii;

typedef pair<ll, ll>          pll;

typedef pair<int, pii>        iii;

typedef vector<int>           vi;

typedef vector<ll>            vl;

typedef vector<pii>           vii;

typedef vector<iii>           viii;

typedef vector<vi>            vvi;

typedef map<int, int>         mapii;

typedef map<int, bool>        mapib;

typedef map<int, string>      mapis;

typedef set<int>              seti;



/**------- Char Chk----------*/

inline bool isLow(char ch){if(ch>='a' && ch<='z') return true; return false;}

inline bool isUpp(char ch){if(ch>='A' && ch<='Z') return true; return false;}

inline bool isDig(char ch){if(ch>='0' && ch<='9') return true; return false;}



/**------- Double Chk----------*/

inline bool are_equal(db a, db b){return fabs(a-b)<numeric_limits<db>::epsilon();}

inline bool less_than(db a, db b){return (b-a) > ((fabs(a)<fabs(b)?fabs(b):fabs(a)) * numeric_limits<db>::epsilon());}

inline bool greater_than(db a, db b){return (a-b) > ((fabs(a)<fabs(b)?fabs(b):fabs(a)) * numeric_limits<db>::epsilon());}



/**------- Functions ---------*/



template<typename T> string toString(T x){stringstream ss; ss<<x; return ss.str();}

template<typename T> T stringToT(string s, T a){T p; istringstream ss(s); ss>>p; return p;}

template<typename T> T SOD(T n){__typeof(n) sum=0, i=1; for(; i*i<=n; i++) sum += (n%i)?0:((sq(i)==n)?i:i+n/i); return sum;}

template<typename T, typename S> ostream& operator << (ostream& os, const pair<T, S> &v){os << "(" << v.ff << ", " << v.se << ")";return os;}

template<typename T, typename S> ostream& operator << (ostream& os, const map<T, S> &v){for(auto it : v) os << it.ff << " : " << it.se nl; return os;}

template<typename T>ostream& operator << (ostream& os, const set<T> &v){ os << "["; for(auto it : v){os << it;if(it != *v.rbegin())os << ", ";}os << "]";return os;}

template<typename T>ostream& operator << (ostream& os, const vector<T> &v){os << "["; for(int i=0; i<v.size(); i++){ os << v[i]; if(i != sz(v)-1) os << ", ";} os << "]"; return os;}



/**--------Loops--------------*/

#define frab(i, a, b)      for(__typeof(b) i=(a); i<=(b); i++)

#define fr0(i, n)          frab(i, 0, n-1)

#define fr1(i, n)          frab(i, 1, n)

#define rfab(i, a, b)       for(__typeof(b) i=(b); i>=(a); i--)

#define rf0(i, n)           rfab(i, 0, n-1)

#define rf1(i, n)           rfab(i, 1, n)



/**------- Scanf----------*/

#define sf                 scanf

#define sfs(a)             scanf("%s", a)

#define sfc(a)             scanf("%c", &a)

#define sfi(a)             scanf("%d", &a)

#define sfd(a)             scanf("%lf", &a)

#define sfl(a)             scanf("%lld", &a)

#define sfu(a)             scanf("%llu", &a)

#define sfin(a, i, n)       fr0(i, n) sfi(a[i])

#define sfln(a, i, n)       fr0(i, n) sfl(a[i])

#define sfii(a, b)         scanf("%d %d", &a, &b)

#define sfdd(a, b)         scanf("%lf %lf", &a, &b)

#define sfll(a, b)         scanf("%lld %lld", &a, &b)

#define sfuu(a, b)         scanf("%llu %llu", &a, &b)

#define sfiii(a, b, c)     scanf("%d %d %d", &a, &b, &c)

#define sfddd(a, b, c)     scanf("%lf %lf %lf", &a, &b, &c)

#define sflll(a, b, c)     scanf("%lld %lld %lld", &a, &b, &c)

#define sfuuu(a, b, c)     scanf("%llu %llu %llu", &a, &b, &c)



/**------- Printf----------*/

#define pf                 printf

#define pnl                puts("")

#define pfgap              printf(" ")

#define pfig(a)            printf("%d ", a)

#define pfc(a)             printf("%c\n", a)

#define pfi(a)             printf("%d\n", a)

#define pfs(a)             printf("%s\n", a)

#define pflg(a)            printf("%lld ", a)

#define pfl(a)             printf("%lld\n", a)

#define pfu(a)             printf("%llu\n", a)

#define pfd(a)             printf("%.2lf\n", a)

#define pfii(a, b)         printf("%d %d\n", a, b)

#define pfll(a, b)         printf("%lld %lld\n", a, b)

#define pfuu(a, b)         printf("%llu %llu\n", a, b)

#define pfdd(a, b)         printf("%.2lf %.2lf\n", a, b)

#define pfiii(a, b, c)     printf("%d %d %d\n", a, b, c)

#define pflll(a, b, c)     printf("%lld %lld %lld\n", a, b, c)

#define pfuuu(a, b, c)     printf("%llu %llu %llu\n", a, b, c)

#define pfin(a, i, n)       fr0(i, n) {if(i) pfgap; pfig(a[i]);}

#define pfln(a, i, n)       fr0(i, n) {if(i) pfgap; pflg(a[i]);}

#define pfddd(a, b, c)     printf("%.2lf %.2lf %.2lf\n", a, b, c)



/**--------File------------*/

#define inOut              {input; output;}

#define Case               printf("Case %d: ", cases)

#define input              freopen("input.txt","r",stdin)

#define Casepp             cout << "Case " << cases << ": "

#define output             freopen("output.txt","w",stdout)



/**--------Constant------------*/

#define eps                1e-9

#define mx2                101

#define mx3                1001

#define mx4                10001

#define mx5                100001

#define mx6                1000001

#define INF                0x3f3f3f3f



/**-------Upper & Lower Bound-------*/

#define LB(a, v)            (lower_bound(all(a), v))

#define UB(a, v)            (upper_bound(all(a), v))



/**--------DeBug------------*/

#define watch(x)            cout<<(#x)<<" is "<<x<<"\n"

#define chk                 cout<<"Wtf"<<"\n"



const int mod = 1e9 + 7;

const int mx  = 1005;



int n, m;

string s[mx];

int vis[mx][mx];

int dis[mx][mx];



priority_queue< iii, vector<iii>, greater<iii> > pq;



int dx[4] = {-1, 0, 1, 0};

int dy[4] = {0, -1, 0, 1};



bool ok(int x, int y){

    return x>=0 && x<n && y>=0 && y<m && !vis[x][y];}



int main(){FasterIO;



    cin >> n >> m;

    fr0(i, n) cin >> s[i];

    fr0(i, n) fr0(j, m){

        dis[i][j] = INF;

        if(s[i][j] == '#'){

            vis[i][j] = 1;

            dis[i][j] = 0;

            pq.push({0, {i, j}});

        }

    }



    while(pq.size()){

        iii tmp = pq.top(); pq.pop();

        int x = tmp.se.ff, y = tmp.se.se;

        for(int i=0; i<4; i++){

            int xx = x + dx[i];

            int yy = y + dy[i];

            if(ok(xx, yy)){

                vis[xx][yy] = 1;

                dis[xx][yy] = dis[x][y]+1;

                pq.push({dis[xx][yy], {xx, yy}});

            }

        }

    }



    int ans = 0;

    fr0(i, n) ans = max(ans, *max_element(dis[i], dis[i]+m));

    cout << ans nl;

    return 0;

}