// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

using uint = unsigned int;

using ll = long long;

using ld = long double;

using ull = unsigned long long;

using pii = pair<int, int>;

using pll = pair<ll, ll>;

#define dbg(x) cerr<<#x": "<<(x)<<endl

#define dbg_p(x) cerr<<#x": "<<(x).first<<' '<<(x).second<<endl

#define dbg_v(x, n) {cerr<<#x"[]: ";for(long long _=0;_<n;++_)cerr<<(x)[_]<<' ';cerr<<endl;}

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

#define fi first

#define se second



template<typename T1, typename T2>

ostream& operator <<(ostream &out, const pair<T1, T2> &item) {

	out << '(' << item.first << ", " << item.second << ')';

	return out;

}



template <typename T>

ostream& operator <<(ostream &out, const vector<T>& v) {

	for(const auto &item : v) out << item << ' ';

	return out;

}



const int N = 1010;

const int dl[] = { -1, 0, 1, 0 };

const int dc[] = { 0, 1, 0, -1 };



char s[N];

int d[N][N];



int main()

{

	ios_base::sync_with_stdio(false);

	

	memset(d, -1, sizeof d);



	int m, n;

	queue<pii> q;



	cin >> m >> n;

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

		cin >> s;

		for(int j = 0; j < n; ++j)

			if(s[j] == '#') q.push({i, j}), d[i][j] = 0;

	}



	int ans = 0;

	while(!q.empty()) {

		int x = q.front().fi;

		int y = q.front().se;

		q.pop();



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

			int a = x + dl[i];

			int b = y + dc[i];

			if(0 <= a && a < m && 0 <= b && b < n && d[a][b] == -1) {

				d[a][b] = 1 + d[x][y];

				q.push({a, b});

				ans = max(ans, d[a][b]);

			}

		}

	}



	cout << ans << '\n';

	return 0;

}


// Optimized solution to the same problem (faster):
# include <iostream>

# include <queue>

# include <climits>

using namespace std;

 

int H;

int W;

char A[1005][1005];

int counter=0;

int shortestpath[1005][1005];

bool visited[1005][1005];

int maximum=INT_MIN;

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

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

queue< pair<int, int> > starting;



bool inside (int row, int column)

{

    if (row<0 || row>H || column<0 || column>W)

    {

        return false;

    }



    return true;

}



void bfs (queue< pair<int, int> > starting)

{

    queue< pair<int, int> > q;



    while (!starting.empty())

    {

        q.push(make_pair(starting.front().first, starting.front().second));

        visited[starting.front().first][starting.front().second]=true;

        starting.pop();

    }



    while (!q.empty())

    {

        pair<int, int> u=q.front();

        q.pop();



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

        {

            int nextrow=u.first+dr[i];

            int nextcolumn=u.second+dc[i];



            if (inside(nextrow, nextcolumn) && !visited[nextrow][nextcolumn])

            {

                shortestpath[nextrow][nextcolumn]=shortestpath[u.first][u.second]+1;

                q.push(make_pair(nextrow, nextcolumn));

                visited[nextrow][nextcolumn]=true;

            }

        }



    }

}



int main()

{

    cin>>H>>W;



    for (int i=1; i<=H; i++)

    {

        for (int j=1; j<=W; j++)

        {

            cin>>A[i][j];



            if (A[i][j]=='#')

            {

                starting.push(make_pair(i, j));

            }

        }

    }



    bfs(starting);



    for (int i=1; i<=H; i++)

    {

        for (int j=1; j<=W; j++)

        {

            if (shortestpath[i][j]>maximum)

            {

                maximum=shortestpath[i][j];

            }

        }

    }



    cout<<maximum<<endl;

}

// Fastest known solution for this problem: