Cod sursa(job #2017322)

Utilizator Stefan_RaduStefan Radu Stefan_Radu Data 31 august 2017 21:12:33
Problema Barbar Scor 40
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.92 kb
#include <fstream>
#include <vector>
#include <queue>
#include <cmath>

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, 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;

      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, vector < vector < bool > > &used) {

  if (found_path) return;
  if (dist_drag[me.first][me.second] < min_dist or 
    v[me.first][me.second] == '*') {
    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 (used[row][col]) continue;

    used[row][col] = true;
    dfs(min_dist, {row, col}, destination, n, m, found_path, v, dist_drag, used);
    used[row][col] = false;
  }
}

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

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

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];
    v[i] = '*' + 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 = 1; j <= m; j ++) {
      if (v[i][j] == 'D') {
        q.push({i, j});
      }
      else if (v[i][j] == 'I') {
        me = {i, j};
      }
      else if (v[i][j] == 'O') {
        destination = {i, j};
      }
    }
  }

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

  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;
    vector < vector < bool > > used(n + 1, vector < bool > (m + 1));
    used[me.first][me.second] = true;
    dfs(min_dist + (1 << i), me, destination, n, m, found_path, v, dist_drag, used);

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

  cout << sol << '\n';

  return 0;
}