《啊哈!算法》-第 4 章:万能的搜索

浏览: 23 发布日期: 2017-07-26 分类: c

深度优先搜索

深度优先搜索(Depth First Search, DFS)。理解深度优先搜索的关键在于解决“当下该如何做”。至于“下一步该如何做”则与“当下该如何做”是一样的。下面的代码就是深度优先搜索的基本模型:

void dfs(int step) {
    // 判断边界
    // 尝试每一种可能
    for (i = 1; i <= n; i++) {
        // 继续下一步
        dfs(step + 1);
    }
    // 返回
}

发明深度优先算法的是 John E. Hopcroft(约翰·霍普克洛特)和 Robert E. Tarjan(罗伯特·陶尔扬)。

使用深度优先搜索解决问题

[][][] + [][][] = [][][] 问题

#include <stdio.h>
#define NUM 10

int a[NUM], book[NUM];

void dfs(int step) {
  int i;

  if (step == 10) {
    if (
      (a[1] * 100 + a[2] * 10 + a[3]) + (a[4] * 100 + a[5] * 10 + a[6]) == a[7] * 100 + a[8] * 10 + a[9]
    ) {
      for (i = 1; i <= 9; i++) {
        printf("%d", a[i]);
      }

      printf("\n");
    }
  }

  for (i = 1; i <= 9; i++) {
    if (book[i] == 0) {
      a[step] = i;
      book[i] = 1;
      dfs(step + 1);
      book[i] = 0;
    }
  }
}

int main(void) {
  dfs(1);

  return 0;
}

全排列

#include <stdio.h>
#define NUM 10

int a[NUM], book[NUM], n;

void dfs(int step) {
  int i;

  if (step == n + 1) {
    for (i = 1; i <= n; i++) {
      printf("%d", a[i]);
    }

    printf("\n");

    return;
  }

  for (i = 1; i <= n; i++) {
    if (book[i] == 0) {
      a[step] = i;
      book[i] = 1;
      dfs(step + 1);
      book[i] = 0;
    }
  }
}

int main(void) {
  scanf("%d", &n);

  dfs(1);

  return 0;
}

解救小哈

方向感不好的小哈在迷宫里迷路了。小哼得知后便立即去解救小哈。假如小哼已经知道迷宫的地图和小哈的位置,且迷宫中有障碍物,小哼是不能够到达的。那么求出小哼怎样走能够最快的找到小哈?

地图由一个二维数组组成,用 0 表示可到达的位置,2 表示不可到达的位置:

int a[4][4] = {
  {0, 0, 2, 0},
  {0, 0, 0, 2},
  {0, 2, 0, 0},
  {0, 0, 0, 0}
};

得知小哈的位置在(2, 2)

#include <stdio.h>

int a[4][4] = {
  {0, 0, 2, 0},
  {0, 0, 0, 2},
  {0, 2, 0, 0},
  {0, 0, 0, 0}
};
int book[4][4], tx, ty, min = 9999;
int forward[4][2] = {
  {-1, 0},
  {0, 1},
  {1, 0},
  {0, -1}
};

void dfs(int x, int y, int step) {
  int i;

  // 边界
  if (x == 2 && y == 2) {
    if (step < min) {
      min = step;
    }
    
    // 返回
    return;
  }

  // 尝试每一种可能
  for (i = 0; i < 4; i++) {
    tx = x + forward[i][0];
    ty = y + forward[i][1];

    if (tx >= 0 || tx < 4 || ty >=0 || ty < 4) {
      if (a[tx][ty] == 0 && book[tx][ty] == 0) {
        book[tx][ty] = 1;
        // 继续下一步
        dfs(tx, ty, step + 1);
        book[tx][ty] = 0;
      }
    }
  }
}

int main(void) {
  int i, j;

  for (i = 0; i < 4; i++)
    for(j = 0; j < 4; j++)
      book[i][j] = 0;

  book[0][0] = 1;

  dfs(0, 0, 0);

  printf("%d\n", min);

  return 0;
}

炸弹人

#include <stdio.h>
#define NUM 13

char a[NUM][NUM] = {
  {'#','#','#','#','#','#','#','#','#','#','#','#','#'},
  {'#','G','G','.','G','G','G','#','G','G','G','.','#'},
  {'#','#','#','.','#','G','#','G','#','G','#','G','#'},
  {'#','.','.','.','.','.','.','.','#','.','.','G','#'},
  {'#','G','#','.','#','#','#','.','#','G','#','G','#'},
  {'#','G','G','.','G','G','G','.','#','.','G','G','#'},
  {'#','G','#','.','#','G','#','.','#','.','#','.','#'},
  {'#','#','G','.','.','.','G','.','.','.','.','.','#'},
  {'#','G','#','.','#','G','#','#','#','.','#','G','#'},
  {'#','.','.','.','G','#','G','G','G','.','G','G','#'},
  {'#','G','#','.','#','G','#','G','#','.','#','G','#'},
  {'#','G','G','.','G','G','G','#','G','.','G','G','#'},
  {'#','#','#','#','#','#','#','#','#','#','#','#','#'}
};
int book[NUM][NUM];
int max = 0, amount, p, q;
int direction[4][2] = {
  {-1, 0},
  {0, 1},
  {1, 0},
  {0, -1}
};

int getNum(int i, int j) {
  // 杀上边的怪
  int x = i;
  int y = j;
  int num = 0;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    x -= 1;          
  }

  // 杀右边的怪
  x = i;
  y = j;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    
    y += 1;
  }

  // 杀下边的怪
  x = i;
  y = j;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    
    x += 1;
  }

  // 杀左边的怪
  x = i;
  y = j;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    
    y -= 1;
  }

  return num;
}

void dfs(int x, int y) {
  int i;

  // 边界判断
  amount = getNum(x, y);
  if (amount > max) {
    max = amount;
    p = x;
    q = y;
  }

  // 尝试每一步
  for (i = 0; i < 4; i++) {
    int tx = x + direction[i][0];
    int ty = y + direction[i][1];
    
    if (tx > 1 || tx < NUM || ty > 1 || ty < NUM) {
      if (a[tx][ty] == '.' && book[tx][ty] == 0) {
        book[tx][ty] = 1;
        // 尝试下一步
        dfs(tx, ty);
      }
    }
  }
}

int main(void) {
  book[3][3] = 1;
  dfs(3, 3);

  printf("(%d, %d) %d\n", p, q, max);

  return 0;
}

使用广度优先搜索解决问题

炸弹人

#include <stdio.h>
#define NUM 13

char a[NUM][NUM] = {
  {'#','#','#','#','#','#','#','#','#','#','#','#','#'},
  {'#','G','G','.','G','G','G','#','G','G','G','.','#'},
  {'#','#','#','.','#','G','#','G','#','G','#','G','#'},
  {'#','.','.','.','.','.','.','.','#','.','.','G','#'},
  {'#','G','#','.','#','#','#','.','#','G','#','G','#'},
  {'#','G','G','.','G','G','G','.','#','.','G','G','#'},
  {'#','G','#','.','#','G','#','.','#','.','#','.','#'},
  {'#','#','G','.','.','.','G','.','.','.','.','.','#'},
  {'#','G','#','.','#','G','#','#','#','.','#','G','#'},
  {'#','.','.','.','G','#','G','G','G','.','G','G','#'},
  {'#','G','#','.','#','G','#','G','#','.','#','G','#'},
  {'#','G','G','.','G','G','G','#','G','.','G','G','#'},
  {'#','#','#','#','#','#','#','#','#','#','#','#','#'}
};
int book[NUM][NUM];
int max = 0;
int direction[4][2] = {
  {-1, 0},
  {0, 1},
  {1, 0},
  {0, -1}
};

int getNum(int i, int j) {
  // 杀上边的怪
  int x = i;
  int y = j;
  int num = 0;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    x -= 1;          
  }

  // 杀右边的怪
  x = i;
  y = j;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    
    y += 1;
  }

  // 杀下边的怪
  x = i;
  y = j;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    
    x += 1;
  }

  // 杀左边的怪
  x = i;
  y = j;

  while (a[x][y] != '#') {
    if (a[x][y] == 'G') {
      num += 1;
    }
    
    y -= 1;
  }

  return num;
}

int main(void) {
  int i, j, tx, ty, amount, p, q;

  for (i = 0; i < NUM; i++)
    for (j = 0; j < NUM; j++)
      book[i][j] = 0;

  // 初始化队列
  struct node {
    int x;
    int y;
  } que[1000];
  int head, tail;
  head = 0;
  tail = 0;
  // 设定????人的位置
  book[3][3] = 1;
  que[tail].x = 3;
  que[tail].y = 3;
  tail++;

  // 广度优先搜索模型
  while (head < tail) {
    for (i = 0; i < 4; i++) {
      tx = que[head].x + direction[i][0];
      ty = que[head].y + direction[i][1];

      // 判断是否跑出地图外
      if (tx > 1 || tx < NUM || ty > 1 || ty < NUM) {
        // 判断该位置是否可用到达
        if (a[tx][ty] == '.' && book[tx][ty] == 0) {
          que[tail].x = tx;
          que[tail].y = ty;
          book[tx][ty] = 1;
          tail++;

          // 计算杀敌数量
          amount = getNum(tx, ty);
          if (amount > max) {
            max = amount;
            p = tx;
            q = ty;
          }
        }
      }
    }

    // 每一个点尝试完毕后,需要出队
    head++;
  }

  printf("(%d, %d) %d\n", p, q, max);

  return 0;
}
返回顶部