0

I have a quite difficult project that I have to make for my university. It's a body scanner and the concept is based on the 1993's ACM Final's problem H, Scanner.

See The Picture Here

Please see the picture to understand the problem.

So, to our point. I need your help for making an algorithm that gets numbers for data input and produces a table (10x15 in our case), based on these numbers. The first 10 numbers represent the number of non white cells in every line (1). The next 24 the number of non white cells in the left to right diagonals (2). The next 15 the number of non white cells in every column (3), and the last 24 the number of non white cells in the right to left diagonals (4). I've been trying to think of an algorithm that combines all these data and create the array, but without results.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
  • 1
    lets see what you've got so far – K Mehta Feb 11 '12 at 15:45
  • I've managed to write some code for filling with '1's the full lines and columns, or '0's the empty lines or columns. I'm working on the full/empty diagonals right now. It's like the solution to pic-a-pix puzzles [(Link here)](http://www.conceptispuzzles.com/index.aspx?uri=puzzle/pic-a-pix/techniques), but I have to combine the diagonals too to my algorithm and it makes it way to complex. – Christos Melas Feb 11 '12 at 15:55
  • You know that there is a solution at the page you are linking, right? – MK. Feb 11 '12 at 16:13
  • MK, of course I've noticed the sample solution, but I can't just copy and paste the solution to my work. I can't use something that I don't comprehend. That solution works great, but I can't understand the logic of the programmer. – Christos Melas Feb 11 '12 at 16:19
  • @Someone I think figuring out the code there by yourself is a good exercise. – MK. Feb 11 '12 at 18:03
  • Of course, that's why I just don't copy paste the sample solution too. But I still find it quite difficult. – Christos Melas Feb 11 '12 at 18:10

3 Answers3

1

Well, the lines and columns are easy. They're just the x or y coordinate.

The game is detecting the diagonals.

And that's not super hard if you think a bit about it.

Consider:

a
ba
cba
dcba
edcba

With a little study you can see the relationship between the cells and the diagonal.

But what about the other half of the table?

Consider this:

a
ba
cba
dcba
-----
edcba
fedcb
gfedc
hgfed
ihgfe
-----
 ihgf
  ihg
   ih
    i

The lines are the boundaries of the table, but you can see the diagonals simply project from "outside" the table. So once you can solve the basic case (for the ones on the table), just "make your table bigger" so to speak. For example, to find out the diagonal for the 'a' in the upper right corner, you may well end up with the "diagonal number" being, oh, -4 or -5 (something like that). Just shift it back (ie. add 4 or 5) along with the rest, and that moves the 'a' diagonal to 0 (or wherever you want it).

But in the end, the diagonal and other determinants are simply functions based on the coordinates. Work out those equations, and your done.

Will Hartung
  • 115,893
  • 19
  • 128
  • 203
  • Thank you, I'm working on my equations right now. I found the equations for the left-to-right diagonal, now I'm working on the equations for the right-to-left diagonal. – Christos Melas Feb 11 '12 at 17:15
1

The general answer to this is that it's like a CAT scan and there is a very nice introductory article Saving lives: the mathematics of tomography that gives a light overview of how it's really done (invert the Radon transform using a Fourier transform).

On the other hand, I find it hard to believe that a programming competition expected you to do that, so I suspect that for simple cases one can treat this as a constraint satisfaction problem, so you can try searching the space of possible solutions and cutting off the search wherever the solution doesn't match the constraints. Depending on how you structure your search and how efficiently you check your constraints, this might be efficient enough for small problems.

Liudvikas Bukys
  • 5,790
  • 3
  • 25
  • 36
1

I like logic exercises too much to let this one pass me by, and so I spent a while working out a solution in javascript. First the code creates a table to display results and to serve as a data structure, then there are four functions for checking horizontal, vertical and both diagonal lines. Each of those four functions has the same form: on each line, find the number of free cells with no values set, and the number of full cells containing the body. Then, if there are exactly enough free cells for the remaining cells containing the body, fill those. Finally, if there are no remaining cells containing the body, mark remaining free cells as empty.

After that, all that is left is rinse and repeat. Each time one of the four functions is run, more cells are marked as full or empty, enabling the next function to do the same with more constraints in place. Three passes from all four functions solves your sample problem, though larger and more complex shapes will certainly require more, if they can be solved at all. I can easily imagine shapes that this method would fail to solve.

function create(rows, cols) {
  var table = document.createElement('table');
  for (var i = 0; i < rows; i++) {
    var row = table.insertRow(-1);
    for (var k = 0; k < cols; k++) {
      var cell = row.insertCell(-1);
      cell.value = null;
      cell.innerHTML = '&nbsp;';
      cell.style.width = '15px';
      cell.style.backgroundColor = '#cccccc';
    }
  }
  table.maxrow = rows - 1;
  table.maxcol = cols - 1;
  document.body.appendChild(table);
  return table;
}
function checkRows(table, rows) {
  for (var i = 0; i < rows.length; i++) {
    var free = 0;
    var full = 0;
    for (var k = 0; k <= table.maxcol; k++) {
      if (table.rows[i].cells[k].value == null) {
        free++;
      } else if (table.rows[i].cells[k].value == 1) {
        full++;
      }
    }
    if (free == 0) {
      continue;
    } else if (rows[i] - full == free) {
      for (var k = 0; k <= table.maxcol; k++) {
        if (table.rows[i].cells[k].value == null) {
          table.rows[i].cells[k].style.backgroundColor = '#ffcccc';
          table.rows[i].cells[k].value = 1;
        }
      }
    } else if (rows[i] - full == 0) {
      for (var k = 0; k <= table.maxcol; k++) {
        if (table.rows[i].cells[k].value == null) {
          table.rows[i].cells[k].style.backgroundColor = '#ccffcc';
          table.rows[i].cells[k].value = 0;
        }
      }
    }
  }
}
function checkCols(table, cols) {
  for (var i = 0; i < cols.length; i++) {
    var free = 0;
    var full = 0;
    for (var k = 0; k <= table.maxrow; k++) {
      if (table.rows[k].cells[i].value == null) {
        free++;
      } else if (table.rows[k].cells[i].value == 1) {
        full++;
      }
    }
    if (free == 0) {
      continue;
    } else if (cols[i] - full == free) {
      for (var k = 0; k <= table.maxrow; k++) {
        if (table.rows[k].cells[i].value == null) {
          table.rows[k].cells[i].style.backgroundColor = '#ffcccc';
          table.rows[k].cells[i].value = 1;
        }
      }
    } else if (cols[i] - full == 0) {
      for (var k = 0; k <= table.maxrow; k++) {
        if (table.rows[k].cells[i].value == null) {
          table.rows[k].cells[i].style.backgroundColor = '#ccffcc';
          table.rows[k].cells[i].value = 0;
        }
      }
    }
  }
}
function checkDiagonals1(table, diagonals) {
  for (var i = 0; i < diagonals.length; i++) {
    var row = i;
    var col = 0;
    if (i > table.maxrow) {
      row = table.maxrow;
      col = i - row;
    }
    var free = 0;
    var full = 0;
    for (var k = 0; k <= row && col + k <= table.maxcol; k++) {
      if (table.rows[row - k].cells[col + k].value == null) {
        free++;
      } else if (table.rows[row - k].cells[col + k].value == 1) {
        full++;
      }
    }
    if (free == 0) {
      continue;
    } else if (diagonals[i] - full == free) {
      for (var k = 0; k <= row && col + k <= table.maxcol; k++) {
        if (table.rows[row - k].cells[col + k].value == null) {
          table.rows[row - k].cells[col + k].style.backgroundColor = '#ffcccc';
          table.rows[row - k].cells[col + k].value = 1;
        }
      }
    } else if (diagonals[i] - full == 0) {
      for (var k = 0; k <= row && col + k <= table.maxcol; k++) {
        if (table.rows[row - k].cells[col + k].value == null) {
          table.rows[row - k].cells[col + k].style.backgroundColor = '#ccffcc';
          table.rows[row - k].cells[col + k].value = 0;
        }
      }
    }
  }
}
function checkDiagonals2(table, diagonals) {
  for (var i = 0; i < diagonals.length; i++) {
    var row = table.maxrow;
    var col = i;
    if (i > table.maxcol) {
      row = table.maxrow - i + table.maxcol;
      col = table.maxcol;
    }
    var free = 0;
    var full = 0;
    for (var k = 0; k <= row && k <= col; k++) {
      if (table.rows[row - k].cells[col - k].value == null) {
        free++;
      } else if (table.rows[row - k].cells[col - k].value == 1) {
        full++;
      }
    }
    if (free == 0) {
      continue;
    } else if (diagonals[i] - full == free) {
      for (var k = 0; k <= row && k <= col; k++) {
        if (table.rows[row - k].cells[col - k].value == null) {
          table.rows[row - k].cells[col - k].style.backgroundColor = '#ffcccc';
          table.rows[row - k].cells[col - k].value = 1;
        }
      }
    } else if (diagonals[i] - full == 0) {
      for (var k = 0; k <= row && k <= col; k++) {
        if (table.rows[row - k].cells[col - k].value == null) {
          table.rows[row - k].cells[col - k].style.backgroundColor = '#ccffcc';
          table.rows[row - k].cells[col - k].value = 0;
        }
      }
    }
  }
}

var rows = new Array(10, 10, 6, 4, 6, 8, 13, 15, 11, 6);
var cols = new Array(2, 4, 5, 5, 7, 6, 7, 10, 10, 10, 7, 3, 3, 5, 5);
var diagonals1 = new Array(0, 1, 2, 2, 2, 2, 4, 5, 5, 6, 7, 6, 5, 6, 6, 5, 5, 6, 6, 3, 2, 2, 1, 0);
var diagonals2 = new Array(0, 0, 1, 3, 4, 4, 4, 4, 3, 4, 5, 7, 8, 8, 9, 9, 6, 4, 4, 2, 0, 0, 0, 0);
var table = create(rows.length, cols.length);

checkRows(table, rows);
checkCols(table, cols);
checkDiagonals1(table, diagonals1);
checkDiagonals2(table, diagonals2);
Feysal
  • 623
  • 4
  • 7
  • I'm going to check this solution out tomorrow. I think that it will work, thank you so much. – Christos Melas Feb 12 '12 at 04:12
  • Just one question, what does the "continue" expression in javascript? I don't know java yet, only C. – Christos Melas Feb 12 '12 at 04:40
  • See here for a brief explanation of what `continue` does: http://en.wikipedia.org/wiki/Control_flow#Continuation_with_next_iteration. It is a basic construct found in any language, though not always with the same name. Here I am using it to stop execution of a loop iteration if no free cells were found, since there is nothing to do in such cases. – Feysal Feb 12 '12 at 09:46