- 分享
二维数组高阶技巧
- @ 2025-3-27 15:21:42
#竞赛/技巧
一、动态规划与二维数组的化学反应
1. 经典模型
// 数字三角形最大路径和(NOIP 2005普及组真题)
for(int i = n-2; i >=0; i--)
for(int j=0; j<=i; j++)
dp[i][j] += max(dp[i+1][j], dp[i+1][j+1]);
// 网格路径计数(注意初始化边界)
dp[0][0] = 1;
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
if(grid[i][j] !=障碍)
dp[i][j] += dp[i-1][j] + dp[i][j-1];
2. 状态压缩技巧
// 滚动数组优化(适用于只需要前一行状态的DP)
int dp[2][N]; // 奇偶滚动
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
dp[i%2][j] = max(dp[(i-1)%2][j], dp[i%2][j-1]) + val;
二、二维差分高阶应用
1. 区域修改模板
// 给子矩阵(x1,y1)-(x2,y2)增加k
diff[x1][y1] += k;
diff[x1][y2+1] -= k;
diff[x2+1][y1] -= k;
diff[x2+1][y2+1] += k;
// 最终通过二维前缀和还原
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
diff[i][j] += diff[i-1][j] + diff[i][j-1] - diff[i-1][j-1];
2. 真题应用场景
-
图像滤镜处理(区域模糊/锐化)
-
棋盘覆盖问题
-
实时统计区域最大值
三、特殊遍历模式扩展
1. Z字形遍历(适合矩阵压缩场景)
for(int i=0; i<n; i++){
if(i%2 ==0)
for(int j=0; j<m; j++) cout << a[i][j];
else
for(int j=m-1; j>=0; j--) cout << a[i][j];
}
2. 菱形遍历(处理中心扩散问题)
int directions[4][2] = {{1,1}, {1,-1}, {-1,-1}, {-1,1}}; // 四象限扩散
for(int step=1; step<=radius; step++)
for(int dir=0; dir<4; dir++)
for(int k=0; k<step; k++)
// 处理(x+dx*step, y+dy*step)
四、图论问题中的二维映射
1. 网格坐标转换
// 将二维坐标编码为一维(用于并查集/哈希存储)
int hash(int x, int y) { return x*1000 + y; } // 假设列数<1000
// 解码函数
pair<int,int> decode(int num) {
return {num/1000, num%1000};
}
2. BFS优化模板
// 使用方向数组 + 队列
struct Node { int x, y, step; };
queue<Node> q;
bool vis[N][N]; // 必须的访问标记
while(!q.empty()){
auto t = q.front(); q.pop();
for(int i=0; i<4; i++){
int nx = t.x + dx[i], ny = t.y + dy[i];
if(nx>=0 && nx<n && ny>=0 && ny<m && !vis[nx][ny]){
vis[nx][ny] = true;
q.push({nx, ny, t.step+1});
}
}
}
五、输入输出优化秘籍
1. 快速读入模板
inline int read() {
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
// 使用方法
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
a[i][j] = read();
2. 输出优化技巧
// 预先分配缓冲区(减少cout调用次数)
string buf;
for(int i=0; i<n; i++){
for(int j=0; j<m; j++)
buf += to_string(a[i][j]) + " ";
buf += "\n";
}
cout << buf;
六、致命错误案例库
1. 经典翻车现场
// 错误案例1:行列颠倒
int arr[3][4];
for(int i=0; i<4; i++) // 错误!行数应该是3
for(int j=0; j<3; j++) // 错误!列数应该是4
cin >> arr[i][j];
// 错误案例2:忘记初始化
int local_arr[100][100]; // 不会自动初始化为0!
memset(local_arr, -1, sizeof(local_arr)); // 正确做法
2. 越界的幽灵
// 正确边界检查模板
#define inRange(x, y) (x >=0 && x <n && y >=0 && y <m)
// 错误写法:先访问后判断
if(a[x][y] > 0 && x <n && y <m) // 可能已越界!
七、综合训练营
1. 经典变式题
-
矩阵中的最长递增路径(DFS+记忆化)
-
01矩阵中的最大正方形(动态规划)
-
稀疏矩阵的压缩存储(三元组表示法)
2. CSP-J 仿真题
// 2023模拟题:激光路径计算
题目描述:
给定n×m网格,某些格子有反射镜(/ 或 \),
求从左上角向右发射的激光最终位置。
解题思路:
1. 使用方向数组记录光线状态
2. 遇到镜子时改变方向
3. 设置访问标记防止无限循环
八、时空复杂度速查表
| 操作 | 时间复杂度 | 空间复杂度 | 应用场景 |
|---|---|---|---|
| 暴力遍历 | O(n²) | O(1) | 小规模数据(n≤1000) |
| 二维前缀和查询 | O(1) | O(n²) | 频繁子矩阵求和 |
| BFS搜索最短路径 | O(nm) | 迷宫类问题 | |
| 动态规划路径计数 | 网格路径问题 | ||
| 矩阵快速幂 | O(n³logk) | O(n²) | 矩阵递推问题(进阶) |
0 条评论
目前还没有评论...