直接遍历统计,但是能够发现有部分是重复的,需要把问题分成4个相同的小问题,在边长为9的时候,分成4个4*5的矩形和最中间的那个点。把飞或者角固定在这个小矩形范围内,另一个棋子则可以无限制在棋盘的任意位置,这样将小矩形结果乘以4再加上中间的的可能就可以得到结果,还能减少重复计算。
在对格子的计算中,一种方式是先填标记然后再重新遍历计数,如Python实现,显然,这种方法的效率不高,我们可以将遍历过的格子填上1(初始化为0),然后分别记录遍历过的格子的数目count和遍历时格子中的所有值的和sum,可以发现sum就是重复计数的部分。那么count-sum就是没有重复的格子计数值,如C/C++实现。
最后在矩阵的数组表示中,我们采用此书提供的新思路,用给数组添加边界的方式去取代对数组下标的边界判断。
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- using namespace std;
-
- const int SQUARE_LEN = 9;
- const int ARRAY_SIZE = SQUARE_LEN + 2;
-
- const int FLY = -2; // 飞用 -2 标识
- const int KOK = -3; // 角用 -3 标识
-
- // 飞的移动方向
- const int FLY_DET_X[] = { 0, 0, -1, 1 };
- const int FLY_DET_Y[] = { 1, -1, 0, 0 };
-
- // 角的移动方向
- const int KOK_DET_X[] = { -1, -1, 1, 1 };
- const int KOK_DET_Y[] = { -1, 1, -1, 1 };
-
- int square[ARRAY_SIZE][ARRAY_SIZE];
-
- void init_square()
- {
- memset(square, 0, sizeof(square)); // 全部置为 0
-
- // 将边界置为 -1
- for (int i = 0; i < SQUARE_LEN + 2; i++)
- {
- square[0][i] = square[ARRAY_SIZE - 1][i] = -1;
- square[i][0] = square[i][ARRAY_SIZE - 1] = -1;
- }
- }
-
- void show_square()
- {
- for (int i = 0; i < ARRAY_SIZE; i++)
- {
- for (int j = 0; j < ARRAY_SIZE; j++)
- cout << square[i][j] << '\t';
- cout << endl;
- }
- cout << endl;
- }
-
- int get_count(int fly_x, int fly_y, int kok_x, int kok_y)
- {
- init_square();
-
- square[fly_x][fly_y] = FLY;
- square[kok_x][kok_y] = KOK;
-
- int count = 0, redundant = 0;
-
- // 统计飞的格子
- for (int i = 0; i < 4; i++)
- {
- int tmp_x = fly_x + FLY_DET_X[i], tmp_y = fly_y + FLY_DET_Y[i];
- while (square[tmp_x][tmp_y] >= 0) // 遇见边界(-1)或另一个棋子停下
- {
- count++;
- square[tmp_x][tmp_y] = 1; // 用 1 标识 filled
- tmp_x += FLY_DET_X[i];
- tmp_y += FLY_DET_Y[i];
- }
- }
-
- // 统计角的格子
- for (int i = 0; i < 4; i++)
- {
- int tmp_x = kok_x + KOK_DET_X[i], tmp_y = kok_y + KOK_DET_Y[i];
- while (square[tmp_x][tmp_y] >= 0) // 遇见边界(-1)或另一个棋子停下(-2,-3)
- {
- count++;
- redundant += square[tmp_x][tmp_y];
- square[tmp_x][tmp_y] = 1; // 用 1 标识 filled
- tmp_x += KOK_DET_X[i];
- tmp_y += KOK_DET_Y[i];
- }
- }
-
- return count - redundant;
- }
-
- int main()
- {
- int total_count = 0;
-
- int mid1 = (SQUARE_LEN + 1) / 2;
- int mid2 = SQUARE_LEN / 2;
-
- // 计算飞在 1/4 个正方形的可能
- for (int fly_x = 1; fly_x <= mid1; fly_x++)
- for (int fly_y = 1; fly_y <= mid2; fly_y++)
- for (int kok_x = 1; kok_x <= SQUARE_LEN; kok_x++)
- for (int kok_y = 1; kok_y <= SQUARE_LEN; kok_y++)
- {
- if (kok_x == fly_x && kok_y == fly_y)
- continue;
- total_count += get_count(fly_x, fly_y, kok_x, kok_y);
- }
- total_count <<= 2; // total_count * 4
-
- // 当正方形边长是奇数时
- if (SQUARE_LEN % 2)
- {
- for (int kok_x = 1; kok_x <= SQUARE_LEN; kok_x++)
- for (int kok_y = 1; kok_y <= SQUARE_LEN; kok_y++)
- {
- if (kok_x == mid1 && kok_x == kok_y)
- continue;
- total_count += get_count(mid1, mid1, kok_x, kok_y);
- }
- }
-
- cout << total_count << endl;
-
- return 0;
- }
- # coding = utf-8
-
- SQUARE_SIZE = 9
- LIST_SIZE = SQUARE_SIZE + 2
-
- FLY_DXY = ((0, 1), (0, -1), (1, 0), (-1, 0))
- KOK_DXY = ((1, 1), (1, -1), (-1, 1), (-1, -1))
-
-
- def get_count(fly_x, fly_y, kok_x, kok_y):
- # 初始化列表
- board = [[0] * LIST_SIZE for i in range(LIST_SIZE)]
- board[0] = board[LIST_SIZE - 1] = [-1] * LIST_SIZE
- for i in range(LIST_SIZE):
- board[i][0] = board[i][LIST_SIZE - 1] = -1
-
- # 当前两个棋子也赋值负数
- board[fly_x][fly_y] = board[kok_x][kok_y] = -1
-
- # 给格子作标记
- for dx, dy in FLY_DXY:
- x, y = fly_x + dx, fly_y + dy
- while board[x][y] >= 0:
- board[x][y] = 1
- x, y = x + dx, y + dy
-
- # 给角的格子作标记
- for dx, dy in KOK_DXY:
- x, y = kok_x + dx, kok_y + dy
- while board[x][y] >= 0:
- board[x][y] = 1
- x, y = x + dx, y + dy
-
- return sum((sum(item) for item in board)) + 4 * (LIST_SIZE - 1) + 2
-
-
- def get_total_count():
- total_count = 0
- mid1 = (SQUARE_SIZE + 1) // 2
- mid2 = SQUARE_SIZE // 2
-
- for fly_x in range(1, mid1 + 1):
- for fly_y in range(1, mid2 + 1):
- for kok_x in range(1, SQUARE_SIZE + 1):
- for kok_y in range(1, SQUARE_SIZE + 1):
- if kok_x == fly_x and kok_y == fly_y:
- continue
- total_count += get_count(fly_x, fly_y, kok_x, kok_y)
-
- total_count <<= 2
-
- if SQUARE_SIZE % 2:
- fly_x = fly_y = mid1
- for kok_x in range(1, SQUARE_SIZE + 1):
- for kok_y in range(1, SQUARE_SIZE + 1):
- if kok_x == fly_x and kok_y == fly_y:
- continue
- total_count += get_count(fly_x, fly_y, kok_x, kok_y)
-
- return total_count
-
-
- if __name__ == '__main__':
- print(get_total_count())
- pass
-