T20052: 最大点数(同2048规则)
dfs, matrices, http://cs101.openjudge.cn/pctbook/T20052/
【黄浩展 25工学院】思路:先写最简单的左移操作,右移可直接翻转,上移对每列转化为数组进行左移操作,下移为上移翻转,之后递归搜索并更新最大值
cpp
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void mergeleft(vector<int>& line) {
vector<int>nxt, tmp;
for (int n : line)
if (n != 0)
nxt.push_back(n);
line = vector<int>(line.size(), 0);
for (int i = 0; i < nxt.size();) {
if (i + 1 < nxt.size() && nxt[i] == nxt[i + 1]) {
tmp.push_back(2 * nxt[i]);
i += 2;
}
else {
tmp.push_back(nxt[i]);
i++;
}
}
for(int i=0;i<tmp.size();i++)
line[i] = tmp[i];
}
void mergeright(vector<int>& line) {
reverse(line.begin(), line.end());
mergeleft(line);
reverse(line.begin(), line.end());
}
void ml(vector <vector<int>>& grid) {
for (auto &r : grid)
mergeleft(r);
}
void mr(vector<vector<int>>& grid) {
for (auto &r : grid)
mergeright(r);
}
void mu(vector<vector<int>>& grid) {
for (int i = 0; i < grid[0].size(); i++) {
vector<int>tmp;
for (int j = 0; j < grid.size(); j++)
tmp.push_back(grid[j][i]);
mergeleft(tmp);
for (int k = 0; k < grid.size(); k++)
grid[k][i] = (k<tmp.size()?tmp[k]:0);
}
}
void md(vector<vector<int>>& grid) {
reverse(grid.begin(), grid.end());
mu(grid);
reverse(grid.begin(), grid.end());
}
int findmax(vector<vector<int>>& grid) {
int res = 0, m = grid.size(), n = grid[0].size();
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
res = max(res, grid[i][j]);
return res;
}
void dfs(vector<vector<int>>& grid, int step, int& ans, int p) {
ans = max(ans, findmax(grid));
if (step == p) return;
vector<vector<int>>tl = grid, tr = grid, tu = grid, td = grid;
ml(tl);
if(tl!= grid)
dfs(tl, step + 1, ans, p);
mr(tr);
if (tr!= grid)
dfs(tr, step + 1, ans, p);
mu(tu);
if (tu!= grid)
dfs(tu, step + 1, ans, p);
md(td);
if (td!= grid)
dfs(td, step + 1, ans, p);
}
int main() {
int m, n, p;
cin >> m >> n >> p;
vector<vector<int>>grid(m, vector<int>(n));
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
cin >> grid[i][j];
int ans = 0;
dfs(grid, 0, ans, p);
cout << ans << endl;
return 0;
}【江昊中 25数院】思路:一开始觉得题里给的left函数不够优雅, 于是自己重写了一个, 并写了一个统一的滑动接口. 提交后WA, 以为是dfs出错了, 调了二十多分钟才意识到自己的left的移动算法写错了
cpp
#include <bits/stdc++.h>
using namespace std;
using Board = vector<vector<int>>;
// 左右反转矩阵
void reverseRow(Board& board) {
for (auto& row : board) {
reverse(row.begin(), row.end());
}
}
// 转置矩阵
void transpose(Board& board) {
int n = board.size();
int m = board[0].size();
Board tmp(m, vector<int>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
tmp[i][j] = board[j][i];
}
}
board = move(tmp);
}
bool left(Board& board) {
bool changed = false;
int n = board.size();
int m = board[0].size();
for (auto& row : board) {
// 使用快慢指针将非零元素移动到左侧
int blank_idx = 0;
for (int j = 0; j < m; j++) {
if (row[j]) {
if (blank_idx != j) {
row[blank_idx] = row[j];
row[j] = 0;
changed = true;
}
blank_idx++;
}
}
for (int j = 0; j < m - 1; j++) {
if (row[j] && row[j + 1] == row[j]) {
row[j] <<= 1;
row[j + 1] = 0;
changed = true;
}
}
blank_idx = 0;
for (int j = 0; j < m; j++) {
if (row[j]) {
if (blank_idx != j) {
row[blank_idx] = row[j];
row[j] = 0;
changed = true;
}
blank_idx++;
}
}
}
return changed;
}
bool right(Board& board) {
reverseRow(board);
bool changed = left(board);
reverseRow(board);
return changed;
}
bool up(Board& board) {
transpose(board);
bool changed = left(board);
transpose(board);
return changed;
}
bool down(Board& board) {
transpose(board);
bool changed = right(board);
transpose(board);
return changed;
}
enum class Direction {
LEFT,
RIGHT,
UP,
DOWN
};
// 统一的滑动接口
bool slide(Board& board, Direction dir) {
switch (dir) {
case Direction::LEFT:
return left(board);
case Direction::RIGHT:
return right(board);
case Direction::UP:
return up(board);
case Direction::DOWN:
return down(board);
default:
return false;
}
}
int const max_num(const Board& board) {
int res = 0;
for (const auto& row : board) {
for (int num : row) {
res = max(res, num);
}
}
return res;
}
int global_max = 0;
// 深度优先搜索枚举所有可能的操作序列,并记录最大值
void dfs(Board& board, int p, int cur_step) {
if (cur_step == p) {
global_max = max(global_max, max_num(board));
return;
}
Direction dirs[] = {Direction::LEFT, Direction::RIGHT, Direction::UP, Direction::DOWN};
for (Direction dir : dirs) {
Board tmp = board;
if (slide(tmp, dir)) {
dfs(tmp, p, cur_step + 1);
} else {
global_max = max(global_max, max_num(tmp));
}
}
}
int main() {
int n, m, p;
cin >> n >> m >> p;
Board board(n, vector<int>(m));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> board[i][j];
}
}
dfs(board, p, 0);
cout << global_max << endl;
return 0;
}用时60min