Cod sursa(job #893360)

Utilizator alex_unixPetenchea Alexandru alex_unix Data 26 februarie 2013 15:18:04
Problema Barbar Scor 90
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.52 kb

#include <cstdio>

const int MAX_SIZE(1002);
const int WAY(4);
const int X [ ] = {-1,0,1,0};
const int Y [ ] = {0,1,0,-1};

int n, m, best;

int dp [MAX_SIZE] [MAX_SIZE];
bool mark [MAX_SIZE] [MAX_SIZE];

struct coord
{
	int i;
	int j;
} queue [MAX_SIZE * MAX_SIZE], *pop(queue), *push(queue), start, end;

inline int min (int a, int b)
{
	return a < b ? a : b;
}

inline void read (void)
{
	std::freopen("barbar.in","r",stdin);
	std::scanf("%d %d\n",&n,&m);
	int i, j;
	char s [MAX_SIZE];
	for (i = 1 ; i <= n ; ++i)
	{
		std::scanf("%s\n",s + 1);
		for (j = 1 ; j <= m ; ++j)
			if (s[j] == '.')
				continue;
			else if (s[j] == '*')
				dp[i][j] = -1;
			else if (s[j] == 'D')
			{
				dp[i][j] = -1;
				push->i = i;
				push->j = j;
				++push;
			}
			else if (s[j] == 'I')
			{
				start.i = i;
				start.j = j;
			}
			else
			{
				end.i = i;
				end.j = j;
			}
	}
	std::fclose(stdin);
}

inline void print (void)
{
	std::freopen("barbar.out","w",stdout);
	std::printf("%d\n",best ? best : -1);
	std::fclose(stdout);
}

inline void isolate (void)
{
	int i, a(n + 1), b(m + 1);
	for (i = 0 ; i <= a ; ++i)
		dp[0][i] = dp[a][i] = -1;
	for (i = 0 ; i <= b ; ++i)
		dp[i][0] = dp[i][b] = -1;
}

inline void dynamic (void)
{
	int i, j, x, y, k;
	while (pop < push)
	{
		i = pop->i;
		j = pop->j;
		for (k = 0 ; k < WAY ; ++k)
		{
			x = i + X[k];
			y = j + Y[k];
			if (!dp[x][y])
			{
				if (dp[i][j] == -1)
					dp[x][y] = 1;
				else
					dp[x][y] = dp[i][j] + 1;
				push->i = x;
				push->j = y;
				++push;
			}
		}
		++pop;
	}
}

inline bool check (int distance)
{
	pop = queue;
	push = queue + 1;
	queue->i = start.i;
	queue->j = start.j;
	mark[start.i][start.j] = true;
	int i, j, x, y, k;
	bool found(false);
	while (pop < push)
	{
		i = pop->i;
		j = pop->j;
		for (k = 0 ; k < WAY ; ++k)
		{
			x = i + X[k];
			y = j + Y[k];
			if (x == end.i && y == end.j)
			{
				found = true;
				goto Skip;
			}
			if (!mark[x][y] && dp[x][y] >= distance)
			{
				mark[x][y] = true;
				push->i = x;
				push->j = y;
				++push;
			}
		}
		++pop;
	}
	Skip :
	for (register struct coord *iterator(queue) ; iterator < push ; ++iterator)
		mark[iterator->i][iterator->j] = false;
	return found;
}

inline void search (void)
{
	int left(1), right(min(dp[start.i][start.j],dp[end.i][end.j])), middle((left + right) >> 1);
	while (left <= right)
	{
		if (check(middle))
		{
			best = middle;
			left = middle + 1;
		}
		else
			right = middle - 1;
		middle = (left + right) >> 1;
	}
}

int main (void)
{
	read();
	isolate();
	dynamic();
	search();
	print();
	return 0;
}