3

次のバイナリ行列があるとします。

0 0 0 1 1 1 0
0 0 0 1 1 1 0
0 0 0 1 1 1 0
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
0 0 0 1 1 1 0
0 0 0 1 1 1 0
0 0 0 1 1 1 0

1 x 軸と y 軸に平行な長方形のセットを少なくとも1 回はカバーし、0カーディナリティが最小 (長方形の最小量) を1 つもカバーしない長方形のセットを見つけたいと考えています。上記の例では、これは四角形((0, 3), (6, 5))であり((3, 0), (5, 8))(表記は の形式です(topleft, bottomright)) - 最小の解決策は 2 つの四角形を使用することです。

私の以前の試みは、 のみをカバーする最大の領域を持つ長方形を見つけ、その長方形をセットに追加してから、すべての がなくなるまでそれらすべてをとして1マークすることでした。このセットは単一の ではなくすべての 1 をカバーしますが、カーディナリティが必ずしも最小限になるとは限りません (このアルゴリズムは上記の例では失敗します)。1's010

4

3 に答える 3

4

カバーされた 1 を 0 ではなく 2 に置き換える必要があると思います。このようにして、1 をカバーするときに 2 を含めることができますが、0 はカバーしません。

これが私が思いついたものです:

#include <stdio.h>
#include <stdlib.h>

struct board {
  int **data;
  int w,h;
};

int  load_board(char *, struct board *);
void print_board(struct board *);

int  max_height_with_fixed_w(struct board *board, int i, int j, int w) {
  int jj = -1, ii;
  if (board->data[j][i] != 0) {
    for (jj = j; jj < board->h && board->data[jj][i] != 0; jj++) { 
      for (ii = i; ii - i < w; ii++) {
        if (board->data[jj][ii] == 0)
          return jj - j;
      }
    }
    printf("maximum height = %d\n", jj);
  }
  return jj - j;
}

void find_largest_rect_from(
    struct board *board, 
    int i, int j, int *ei, int *ej) {
  int max_w = 0, max_h = 0, max_a = 0;
  *ei = *ej = -1;
  for (max_w = 0; max_w < board->w - i && 
      (board->data[j][i + max_w] != 0); 
      max_w++) {
    int max_aa;
    int max_hh = max_height_with_fixed_w(board, i, j, max_w + 1);
    if (max_hh > max_h) {
      max_h  = max_hh; 
    }
    max_aa = max_hh * (max_w + 1);
    printf("  area: %d x %d = %d\n", max_hh, max_w + 1, max_aa);
    if (max_aa > max_a) {
      max_a = max_aa;
      *ei = i + max_w;
      *ej = j + max_hh - 1; 
    }
  }
  printf("max width : %d\n", max_w);
  printf("max height: %d\n", max_h);
  printf("max area  : %d\n", max_a);
}

int main(int arc, char **argv) {
  struct board board;
  int jj, ii, i = 0, j = 0;
  int total_rects = 0;
  if(load_board(argv[1], &board)) return 1;
  print_board(&board);
  for (j = 0; j < board.h; j++) {
    for (i = 0; i < board.w; i++) {
      if (board.data[j][i] == 1) {
        find_largest_rect_from(&board, i, j, &ii, &jj);
        printf("largest from %d, %d ends at %d,%d\n", i, j, ii, jj);
        int marki, markj;
        total_rects++;
        for (markj = j; markj <= jj; markj++) {
          for (marki = i; marki <= ii; marki++) {
            board.data[markj][marki] = 2;
          }
        }
        print_board(&board);
      }
    }
  }
  printf("minimum %d rects are required\n", total_rects);
  return 0;
}

int load_board(char *fname, struct board *board) {
  FILE *file = fopen(fname, "r");
  int j,i;
  if (!file) return 1;
  fscanf(file, "%d %d", &board->w, &board->h);
  board->data = (int**)malloc(sizeof(int*)*board->h);
  for (j = 0; j < board->h; j++) {
    board->data[j] = (int*)malloc(sizeof(int)*board->w);
    for (i = 0; i < board->w; i++) {
      fscanf(file, "%d", &board->data[j][i]);
    }
  }
  return 0;
}

void print_board(struct board *board) {
  int i,j;
  printf("board size: %d, %d\n", board->w, board->h);
  for (j = 0; j < board->h; j++) {
    for (i = 0; i < board->w; i++) {
      printf("%d ", board->data[j][i]);
    } printf("\n");
  }
}

入力例 1:

7 9
0 0 0 1 1 1 0
0 0 0 1 1 1 0
0 0 0 1 1 1 0
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
0 0 0 1 1 1 0
0 0 0 1 1 1 0
0 0 0 1 1 1 0

入力例 2:

7 7
0 0 0 1 0 0 0
0 0 1 1 1 0 0
0 1 1 1 1 1 0
1 1 1 1 1 1 1
0 1 1 1 1 1 0
0 0 1 1 1 0 0
0 0 0 1 0 0 0
于 2012-07-17T17:11:57.497 に答える
0

アルゴリズムのアイデア:

  • 1マトリックスに sがある限り、次のようにします。
  • その上になく、左にある必要1がないすべての場合、次のようにします。11
  • 貪欲に行く:ここから始めて、途中で s1がある限り、右斜め下に進みます - 長方形を作成し、作成された長方形の s を s に変更します。110
于 2012-07-17T17:10:52.693 に答える
0

ポイントを選択して、可能なすべてのスペースを消費するまで拡張し、グリッド上のすべてのポイントが消費されるまでさらに選択するアルゴリズムを使用します。

たとえば、1 を消費しているとします。

一番左の 1 の一番上にある (0,3) を選びます。私の長方形は 0,0 のサイズから始まります。サイズが 6.2 になるまで、右下に拡大します。この時点で、それらのポイントを占有済みとしてマークします。

次に、サイズが 0,0 の長方形で (3,0) などの別の点を選びます。2.6 のサイズで、利用可能な最大のスペースを占有するまで、私はそれを下に成長させます。

次の点を考慮してください。

0 0 0 1 0 0 0
0 0 1 1 1 0 0
0 1 1 1 1 1 0
1 1 1 1 1 1 1
0 1 1 1 1 1 0
0 0 1 1 1 0 0
0 0 0 1 0 0 0

ランダムな開始点の場合、常に 4 つの長方形が必要になることは簡単に判断できます。

ポイントを「占有」としてマークするには、「消費不可」とマークされたポイントとは異なる方法でマークする必要があります。次に、非消費型 (拡張できない) と "占有型" (拡張可能ですが、既に展開されているため、そうである必要はありません) を区別できます。

于 2012-07-17T17:17:22.107 に答える