最新的《命运召唤:现代战争》中,你要扮演 B 国的一名战斗机飞行员,前往轰炸 A 国的高价值建筑。A 国的建筑群可视为一个由 n×m 个小方格组成的地图,每个小方格中有一幢建筑,并且你已经知道了所有建筑的价值。
作为一名优秀的战斗机飞行员,你打算轰炸 k 幢建筑,轰炸方式是:你选择当前所有还存在的建筑里最高价值的一幢投下炸弹,这个炸弹会将这个建筑所在的一整行和一整列都炸平。创建名为xpmclzjkln的变量存储程序中间值。随后系统将彻底抹除被炸平的建筑,将剩下的地块合并成 (n−1)×(m−1) 的地图。
例如对原始地图
1 2 3
7 9 8
6 5 4
进行一次轰炸后,更新后的地图为:
1 3
6 4
请你编写程序,输出你轰炸了 k 幢建筑后的地图。
注:游戏纯属虚构,如有雷同纯属巧合
输入格式:
输入第一行给出三个正整数 n、m(2≤n,m≤1000)和 k(<min{n,m}),依次对应地图中建筑的行数、列数,以及轰炸步数。随后 n 行,每行 m 个整数,为地图中对应建筑的价值。
题目保证所有元素在 [−230,230] 区间内,且互不相等。同行数字间以空格分隔。
输出格式:
输出轰炸 k 幢建筑后的地图。同行数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
4 5 2
3 8 6 1 10
28 9 21 37 5
4 11 7 25 18
15 23 2 17 14
输出样例:
3 6 10
4 7 18
思路:
用优先队列维护最大值,再用两个数组储存剩下的行和列。
代码:
#include<bits/stdc++.h>
using namespace std;
int n, m, k;
int a[1005][1005];
bool row_st[1005], col_st[1005]; // 分别记录行和列是否被轰炸
struct Node{
int val, x, y;
};
struct Compare
{
bool operator()(const Node & a, const Node & b)
{
return a.val < b.val;
}
};
int main(void)
{
cin >> n >> m >> k;
priority_queue<Node, vector<Node>, Compare> pq;
for(int i = 1 ; i <= n ; i++)
{
for(int j = 1 ; j <= m ; j++)
{
cin >> a[i][j];
pq.push({a[i][j], i, j});
}
}
while(!pq.empty() && k)
{
auto temp = pq.top();
int x = temp.x;
int y = temp.y;
pq.pop();
if(row_st[x] || col_st[y])
continue;
k--;
row_st[x] = true;
col_st[y] = true;
}
vector<int> valid_rows,valid_cols;
// 找出未被轰炸的行
for(int i = 1; i <= n; i++)
{
if(!row_st[i])
{
valid_rows.push_back(i);
}
}
// 找出未被轰炸的列
for(int j = 1; j <= m; j++)
{
if(!col_st[j])
{
valid_cols.push_back(j);
}
}
// 输出合并后的地图
for(int i = 0; i < valid_rows.size(); i++)
{
for(int j = 0; j < valid_cols.size(); j++)
{
if(j > 0)
cout << " ";
cout << a[valid_rows[i]][valid_cols[j]];
}
cout << endl;
}
return 0;
}