Tuesday, January 2, 2018

UVa 810 - A Dicey Problem

Accepted date: 2017-12-29
Run Time: 0.010
Ranking (as of 2018-01-02): 58 out of 401
Language: C++

A cumbersome DFS problem.
I wrote the solution while watching a real die in hand.


/*
  UVa 810 - A Dicey Problem

  To build using Visual Studio 2015:
    cl -EHsc -O2 UVa_810_A_Dicey_Problem.cpp
*/

#include <cstdio>
#include <cstring>
#include <cstdlib>

const int nr_sides = 6, nr_chars_max = 20, R_max = 10, C_max = 10;

enum {start, up, down, left, right};

int R, C, sr, sc, maze[R_max][C_max];

struct state {
  int dir_, t_, f_; // direction, top, face
} states[R_max][C_max][nr_sides + 1][nr_sides + 1];
  // states[r][c][t][f].t_ is non-zero 
  // if postion (r, c) has been visited with the die of top t and face f

const struct {
  int l_, r_;
} next_tops[nr_sides + 1][nr_sides + 1] = // next_tops[t][f]
{
  {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}},
  {{0, 0}, {0, 0}, {3, 4}, {5, 2}, {2, 5}, {4, 3}, {0, 0}},
  {{0, 0}, {4, 3}, {0, 0}, {1, 6}, {6, 1}, {0, 0}, {3, 4}},
  {{0, 0}, {2, 5}, {6, 1}, {0, 0}, {0, 0}, {1, 6}, {5, 2}},
  {{0, 0}, {5, 2}, {1, 6}, {0, 0}, {0, 0}, {6, 1}, {2, 5}},
  {{0, 0}, {3, 4}, {0, 0}, {6, 1}, {1, 6}, {0, 0}, {4, 3}},
  {{0, 0}, {0, 0}, {4, 3}, {2, 5}, {5, 2}, {3, 4}, {0, 0}}
};

int nr_paths;
struct {
  int r_, c_;
} paths[R_max * C_max * nr_sides * nr_sides];

int movable(int r, int c, int t)
{
  if (r < 0 || r >= R || c < 0 || c >= C)
    return -1;
  if (maze[r][c] == -1 || maze[r][c] == t)
    return (r == sr && c == sc) ? 1 : 0;
  else
    return -1;
}

void print_path()
{
  printf("  ");
  for (int count = 9; nr_paths; ) {
    printf("(%d,%d)", paths[nr_paths - 1].r_ + 1, paths[nr_paths - 1].c_ + 1);
    if (!--nr_paths)
      putchar('\n');
    else {
      putchar(',');
      if (!--count) {
        printf("\n  ");
        count = 9;
      }
    }
  }
}

bool trace_back_path(int r, int c, int t, int f, int dir)
{
  paths[nr_paths].r_ = r, paths[nr_paths].c_ = c;
  nr_paths++;
  int pr, pc, pt, pf;
  switch (dir) {
  case start:
    print_path();
    return true;
  case up:
    pr = r + 1, pc = c, pt = abs(nr_sides + 1 - f), pf = t;
    break;
  case down:
    pr = r - 1, pc = c, pt = f, pf = abs(nr_sides + 1 - t);
    break;
  case left:
    pr = r, pc = c + 1, pt = next_tops[t][f].r_, pf = f;
    break;
  case right:
    pr = r, pc = c - 1, pt = next_tops[t][f].l_, pf = f;
    break;
  }
  return trace_back_path(pr, pc, pt, pf, states[pr][pc][pt][pf].dir_);
}

bool dfs(int r, int c, int t, int f, int dir)
{
  state& s = states[r][c][t][f];
  if (s.t_)
    return false;
  s.dir_ = dir, s.t_ = t, s.f_ = f;
  int m;
  if ((m = movable(r - 1, c, t)) >= 0) { // up
    if (m)
      return trace_back_path(r - 1, c, f, abs(nr_sides + 1 - t), up);
    if (dfs(r - 1, c, f, abs(nr_sides + 1 - t), up))
      return true;
  }
  if ((m = movable(r + 1, c, t)) >= 0) { // down
    if (m)
      return trace_back_path(r + 1, c, abs(nr_sides + 1 - f), t, down);
    if (dfs(r + 1, c, abs(nr_sides + 1 - f), t, down))
      return true;
  }
  if ((m = movable(r, c - 1, t)) >= 0) { // left
    if (m)
      return trace_back_path(r, c - 1, next_tops[t][f].l_, f, left);
    if (dfs(r, c - 1, next_tops[t][f].l_, f, left))
      return true;
  }
  if ((m = movable(r, c + 1, t)) >= 0) { // right
    if (m)
      return trace_back_path(r, c + 1, next_tops[t][f].r_, f, right);
    if (dfs(r, c + 1, next_tops[t][f].r_, f, right))
      return true;
  }
  return false;
}

int main()
{
  while (true) {
    char name[nr_chars_max + 1];
    scanf("%s", name);
    if (!strcmp(name, "END"))
      break;
    int t, f;
    scanf("%d %d %d %d %d %d", &R, &C, &sr, &sc, &t, &f);
    sr--, sc--;
    for (int r = 0; r < R; r++)
      for (int c = 0; c < C; c++)
        scanf("%d", &maze[r][c]);
    memset(states, 0, sizeof(states));
    nr_paths = 0;
    printf("%s\n", name);
    if (dfs(sr, sc, t, f, start))
      ;
    else
      puts("  No Solution Possible");
  }
  return 0;
}

No comments:

Post a Comment