天梯——现代战争
第一次做的时候,直接暴力,显然最后超时。
暴力代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=10005;
bool mark1[N]={0},mark2[N]={0};
int p[N][N];
int main(){int n,m,k,a,b;cin>>n>>m>>k;for(int i=0;i<n;i++){for(int j=0;j<m;j++){cin>>p[i][j];}}while(k--){int mx1=0;for(int i=0;i<n;i++){if(mark1[i])continue;for(int j=0;j<m;j++){if(mark2[j])continue;if(p[i][j]>mx1){mx1=p[i][j];a=i;b=j;}}}mark1[a]=1;mark2[b]=1;}for(int i=0;i<n;i++){bool first=true;if(mark1[i])continue;for(int j=0;j<m;j++){if(mark2[j])continue;if(!first)cout<<" ";cout<<p[i][j];first=false;}cout<<endl;}return 0;
}
当前代码运行超时的主要原因在于每次轰炸时都要遍历整个未被标记的地图来寻找最大值,当n
、m
和k
的值较大时,时间复杂度较高,为O(k×n×m)。为了避免超时,可以采用更高效的数据结构和算法来优化查找最大值的过程。
优化思路
可以使用优先队列(堆)来存储每个建筑的信息(包括行、列和价值),并按照价值从大到小排序。这样每次查找最大值的时间复杂度可以降低到O(log(n×m))。在每次轰炸后,更新优先队列,移除被轰炸的行和列上的建筑。
#include <iostream>
#include <queue>
#include <vector>
using namespace std;const int N = 10005;
bool mark1[N] = {0}, mark2[N] = {0};
int p[N][N];// 定义一个结构体来存储建筑信息
struct Bd {int row, col, value;Bd(int r, int c, int v) : row(r), col(c), value(v) {}//结构体或类的构造函数的成员初始化列表// 重载小于运算符,用于优先队列排序,优先队列会按照元素值的大小,将最大的元素放在队顶bool operator<(const Bd& other) const {return value < other.value;}
};
int main() {int n, m, k;cin >> n >> m >> k;// 存储所有建筑信息到优先队列priority_queue<Bd> pq;for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {cin >> p[i][j];pq.push(Bd(i, j, p[i][j]));}}// 进行 k 次轰炸while (k--) {// 找到未被标记的最大价值建筑while (!pq.empty() && (mark1[pq.top().row] || mark2[pq.top().col])) {pq.pop();//把已标记的行或列从优先队列中弹出,继续检查下一个元素}if (pq.empty()) break;int a = pq.top().row;int b = pq.top().col;pq.pop();//弹出目前最大值// 标记该建筑所在的行和列mark1[a] = 1;mark2[b] = 1;}// 输出未被标记的建筑for (int i = 0; i < n; i++) {if (mark1[i]) continue;bool first = true;for (int j = 0; j < m; j++) {if (mark2[j]) continue;if (!first) cout << " ";cout << p[i][j];first = false;}cout << endl;}return 0;
}
通过使用优先队列,优化了查找最大值的过程,从而降低了时间复杂度,避免了超时问题。
注意:
while (!pq.empty() && (mark1[pq.top().row] || mark2[pq.top().col])) {pq.pop();//把已标记的行或列从优先队列中弹出,继续检查下一个元素}
这一步不能省略,他的作用是删除那些已经标记的行或列中的元素。即:
在使用优先队列 pq
存储所有建筑信息时,每次轰炸操作前,优先队列 pq
中可能存在一些已经在之前轰炸中被标记(即所在行或列已经被炸平)的建筑元素。如果不通过这个循环将这些已被标记的元素从优先队列中移除,就会错误地选择这些已经不存在的建筑进行后续处理。