Cod sursa(job #2017345)

Utilizator Stefan_RaduStefan Radu Stefan_Radu Data 31 august 2017 22:08:28
Problema Barbar Scor 30
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.89 kb
#include <fstream>
#include <vector>
#include <queue>
#include <cmath>
#include <string>

using namespace std;

ifstream cin("barbar.in");
ofstream cout("barbar.out");

const int INF = 2e9;

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

bool is_good(int i, int j, int n, int m) {
  return i >= 1 and j >= 1 and i <= n and j <= m;
}

void bfs(pair < int, int > poz, vector < vector < int > > &dist_drag, vector < string > &v, int n, int m) {
  queue < pair < int, int > > q;

  dist_drag[poz.first][poz.second] = 0;
  q.push(poz);

  while (!q.empty()) {
    auto cur = q.front();
    q.pop();
    for (int i = 0; i < 4; i ++) {
      int row = cur.first + di[i];
      int col = cur.second + dj[i];
      int next_dist = dist_drag[cur.first][cur.second] + 1;
      
      if (!is_good(row, col, n, m)) continue;
      if (next_dist >= dist_drag[row][col]) continue;
      if (v[row][col - 1] == 'D') continue;
      if (v[row][col - 1] == '*') continue;

      dist_drag[row][col] = next_dist;
      q.push({row, col});
    }
  }
}

void dfs(int min_dist, pair < int, int > me, pair < int, int > destination, int n, int m,
  bool &found_path, vector < string > &v, vector < vector < int > > &dist_drag) {

  if (found_path) return;

  if (me == destination) {
    found_path = true;
    return;    
  }

  for (int i = 0; i < 4; i ++) {
    int row = me.first + di[i];
    int col = me.second + dj[i];
    if (!is_good(row, col, n, m)) continue;
    if (v[row][col - 1] == '*' or v[row][col - 1] == 'D'
      or dist_drag[me.first][me.second] < min_dist) continue;

    char c = v[row][col - 1];
    v[row][col - 1] = '*';
    dfs(min_dist, {row, col}, destination, n, m, found_path, v, dist_drag);
    v[row][col - 1] = c;
  }
}

void get_dist_drag(int n, int m, queue < pair < int, int > > &q, 
  vector < vector < int > > &dist_drag, vector < string > &v) {

  while (!q.empty()) {
    bfs(q.front(), dist_drag, v, n, m);
    q.pop();
  }
}

int main(int argc, char const *argv[]) {
  int n, m;
  cin >> n >> m;
  vector < string > v (n + 1);

  for (int i = 1; i <= n; i ++) {
    cin >> v[i];
  }

  queue < pair < int, int > > q;
  pair < int, int > me;
  pair < int, int > destination;
  for (int i = 1; i <= n; i ++) {  
    for (int j = 0; j < m; j ++) {
      if (v[i][j] == 'D') {
        q.push({i, j + 1});
      }
      else if (v[i][j] == 'I') {
        me = {i, j + 1};
      }
      else if (v[i][j] == 'O') {
        destination = {i, j + 1};
      }
    }
  }

  vector < vector < int > > dist_drag (n + 1, vector < int > (m + 1, INF));
  get_dist_drag(n, m, q, dist_drag, v);

  int min_dist = 0;
  int sol = -1;

  for (int i = log2(n + m + 1); i > 0; i --) {
    if ((1 << i) > n + m + 1) continue;
    bool found_path = false;

    dfs(min_dist + (1 << i), me, destination, n, m, found_path, v, dist_drag);

    if (found_path) {
      min_dist += (1 << i);
      sol = min_dist;
    }
  }

  cout << sol << '\n';

  return 0;
}