Cod sursa(job #514225)

Utilizator webspiderDumitru Bogdan webspider Data 18 decembrie 2010 00:49:16
Problema Barbar Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.74 kb
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum { Dragon, Free, Wall } CellType;
typedef struct Cell{
  CellType type;
  int cost;
} Cell;

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

typedef struct Pos {
  int X, Y;
  Pos *next;
} Pos;

Pos Start, End;
Pos** queue;
int lq;
Cell** grid;

bool** inQueue;
int N, M;

void allocGrid(int &N, int &M) {
  char cell;
  Pos *element;
  scanf("%d %d\n", &N, &M);
  queue = (Pos**) malloc(N*M*sizeof(Pos*));

  grid = (Cell**) malloc(N*sizeof(Cell*));
  inQueue = (bool**) malloc(N*sizeof(bool*));
  for ( int i = 0; i < N; i++ ) {
    grid[i] = (Cell*) malloc(M*sizeof(Cell));
    inQueue[i] = (bool*) malloc(M*sizeof(bool));
    for ( int j = 0; j < M; j++ ) {
      scanf("%c", &cell);
      switch(cell) {
        case '.': grid[i][j].type = Free; break;
        case 'D': grid[i][j].type = Dragon;
                  element = (Pos*) malloc(sizeof(Pos));
                  element->X = i; element->Y = j;
                  inQueue[i][j] = true;
                  queue[lq++] = element;
                  break;
        case '*': grid[i][j].type = Wall; break;
        case 'I': grid[i][j].type = Free;
                  Start.X = i; Start.Y = j;
                  break;
        case 'O': grid[i][j].type = Free;
                  End.X = i; End.Y = j;
                  break;
        default: break;

      }
    }
    scanf("%c\n", &cell);
  }
}

Cell* cellAt(Pos *pos) {
  return &grid[pos->X][pos->Y];
}

void clearQueue() {
  for(int i = 0; i < lq; i++) {
    inQueue[queue[i]->X][queue[i]->Y] = false;
    free(queue[i]);
  }
  lq = 0;
}

int minDistToCheck;

bool valid1(Pos *pos) {
  return pos->X >= 0 && pos->X < N && pos->Y >= 0 && pos->Y < M && 
         !inQueue[pos->X][pos->Y] && cellAt(pos)->type == Free;

}

bool valid2(Pos *pos) {
  return pos->X >= 0 && pos->X < N && pos->Y >= 0 && pos->Y < M && 
         !inQueue[pos->X][pos->Y] && cellAt(pos)->type != Wall &&
         cellAt(pos)->cost >= minDistToCheck;
 
} 

void enqueue1(Pos *old_pos, Pos *pos) {
  cellAt(pos)->cost = cellAt(old_pos)->cost + 1;
  queue[lq++] = pos;
  inQueue[pos->X][pos->Y] = true;
}

void enqueue2(Pos *old_pos, Pos *pos) {
  queue[lq++] = pos;
  inQueue[pos->X][pos->Y] = true;
}

void eachValidNeibourgh(Pos *pos, bool(*valid)(Pos *pos), void(*block)(Pos *old_pos, Pos *pos )) {
  for (int i = 0; i < 4; i++) {
    Pos *new_pos = (Pos*) malloc(sizeof(Pos));
    new_pos->X = pos->X + dx[i];
    new_pos->Y = pos->Y + dy[i];
    if ( valid(new_pos) ) {
      block(pos, new_pos);
    } else {
      free(new_pos);
    }
  }
} 

bool isEqual(Pos *A, Pos *B) {
  return (A->X == B->X) && (A->Y == B->Y);
}

Pos* copy(Pos A) {
  Pos *ret = (Pos *) malloc(sizeof(Pos));
  memcpy(ret, &A, sizeof(Pos));
  return ret;
} 

void printQueue() {
  for ( int i = 0; i < lq; i++ ) {
    printf("[%d,%d | %d]\n", queue[i]->X, queue[i]->Y, cellAt(queue[i])->cost);
  }
  printf("\n");
}

bool canTraverse(int dist) {
  clearQueue();
  if (cellAt(&Start)->cost >= dist) 
    enqueue2(NULL, copy(Start));
  minDistToCheck = dist;
  for (int i = 0; i < lq; i++) {
    if (isEqual(queue[i], &End)) return true;
    eachValidNeibourgh(queue[i], valid2, enqueue2);
  }
  return false;
}


int main() {
  freopen("barbar.in", "r", stdin);
  freopen("barbar.out", "w", stdout);

  allocGrid(N, M);
  
  for (int i = 0; i < lq; i++) {
    eachValidNeibourgh(queue[i], valid1, enqueue1);      
  }

  /*for (int i = 0; i < N; i++, printf("\n")) 
    for (int j = 0; j < M; j++) {
      printf("%d ", grid[i][j].cost);
    } */

  int step, max_dist;
  for (step = 1; step < (N+M); step <<= 1 );
  for (max_dist = 0; step; step >>= 1) {
    if (canTraverse(max_dist + step)) max_dist += step;
  }
  if (!canTraverse(0)) printf("-1\n");
  else printf("%d\n", max_dist);
}