Cod sursa(job #1588129)

Utilizator stoianmihailStoian Mihail stoianmihail Data 2 februarie 2016 20:33:54
Problema Barbar Scor 80
Compilator c Status done
Runda Arhiva de probleme Marime 3 kb
#include <stdio.h>

#define Smerenie 1000000
#define MAX_Q 4095
#define Nadejde 1000
#define MAX_DIR 4
#define NIL -1

const int delta[MAX_DIR][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

typedef struct {
  int l, c;
} pair;

int N, M, ss;
int qhead, qtail;
pair start, finish;
pair queue[MAX_Q + 1];
pair stack[Smerenie + 1];
int d[Nadejde + 2][Nadejde + 2];
char s[Nadejde + 2][Nadejde + 2];
char seen[Nadejde + 2][Nadejde + 2];

int MAX(int X, int Y) {
  return X > Y ? X : Y;
}

/** Bordeaza matricea. **/
void overFlow(int n, int m) {
  int i, j;

  for (i = 0; i <= n; i++) {
    d[i][0] = d[i][m] = NIL;
  }
  for (j = 0; j <= m; j++) {
    d[0][j] = d[n][j] = NIL;
  }
}

/** Construieste perechea (l, c). **/
pair make(int l, int c) {
  pair tmp;
  tmp.l = l;
  tmp.c = c;
  return tmp;
}

/** Pune in coada (l, c). **/
void enqueue(int l, int c, int dist) {
  queue[qtail] = make(l, c);
  d[l][c] = dist;
  qtail = (qtail + 1) & MAX_Q;
}

/** Ia urmatorul element din coada. **/
void dequeue(int *l, int *c, int *dist) {
  (*l) = queue[qhead].l;
  (*c) = queue[qhead].c;
  (*dist) = d[(*l)][(*c)] + 1;
  qhead = (qhead + 1) & MAX_Q;
}

/** Determina pentru fiecare celula (l, c) distanta pana la cel mai apropiat dragon. **/
void init() {
  int i, l, c, l0, c0, dist;

  do {
    dequeue(&l, &c, &dist);
    for (i = 0; i < MAX_DIR; i++) {
      l0 = l + delta[i][0];
      c0 = c + delta[i][1];
      if (!d[l0][c0]) {
        enqueue(l0, c0, dist);
      }
    }
  } while (qhead != qtail);
}

void refresh() {
  int i, j;

  for (i = 1; i <= N; i++) {
    for (j = 1; j <= M; j++) {
      seen[i][j] = 0;
    }
  }
}

void push(pair u) {
  stack[ss++] = u;
  seen[u.l][u.c] = 1;
}

void pop(pair *u) {
  (*u) = stack[--ss];
}

int fire(int limit) {
  int i;
  pair next, node;

  refresh();
  push(start);
  while (ss) {
    pop(&node);
    for (i = 0; i < MAX_DIR; i++) {
      next = make(node.l + delta[i][0], node.c + delta[i][1]);
      if ((!seen[next.l][next.c]) && (d[next.l][next.c] > limit)) {
        push(next);
      }
    }
  }
  return seen[finish.l][finish.c];
}

int bSearch(int lo, int hi) {
  while (hi - lo > 1) {
    int mid = (lo + hi) >> 1;
    if (fire(mid)) {
      lo = mid;
    } else {
      hi = mid;
    }
  }
  fprintf(stderr, "%d\n", hi);
  return hi - 1;
}

int main(void) {
  int i, j;
  FILE *f = fopen("barbar.in", "r");

  /* Citirea datelor. */
  fscanf(f, "%d %d", &N, &M);
  for (i = 1; i <= N; i++) {
    fscanf(f, "%s", s[i] + 1);
    for (j = 1; j <= M; j++) {
      if (s[i][j] == 'I') {
        start = make(i, j);
      } else if (s[i][j] == 'O') {
        finish = make(i, j);
      } else if (s[i][j] == 'D') {
        enqueue(i, j, 1);
      } else if (s[i][j] == '*') {
        d[i][j] = NIL;
      }
    }
  }
  fclose(f);

  /* Precalculare. */
  overFlow(N + 1, M + 1);
  init();

  /* Calcularea solutiei si afisarea ei. */
  freopen("barbar.out", "w", stdout);
  fprintf(stdout, "%d\n", bSearch(NIL, d[start.l][start.c]));
  fclose(stdout);

  /// Multumim Doamne!
  puts("Doamne ajuta!");
  return 0;
}