蓝桥杯C++大学B组一个月冲刺记录2024/3/22
规则:每日三题
1.星空之夜
夜空深处,闪亮的星星以星群的形式出现在人们眼中,形态万千。
一个星群是指一组非空的在水平,垂直或对角线方向相邻的星星的集合。
一个星群不能是一个更大星群的一部分。
星群可能是相似的。
如果两个星群的形状、包含星星的数目相同,那么无论它们的朝向如何,都认为它们是相似的。
现在,我们用一个二维 01 矩阵来表示夜空,如果一个位置上的数字是 1,那么说明这个位置上有一个星星,否则这个位置上的数字应该是 0。
给定一个夜空二维矩阵,请你将其中的所有星群用小写字母进行标记,标记时相似星群用同一字母,不相似星群用不同字母。
标注星群就是指将星群中所有的 1 替换为小写字母。
哈希 + bfs
这个题有一种非常特别的哈希方式:
计算星群中两两点的欧几里得距离。然后存贮在在double数组里面,每次查询的时候直接遍历这个double数组
(一般哈希都会去查询键值,如果键值过大那么通过求余数的方式映射进一个小数组)
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
const int N = 50;
const int M = 105;
const double ep = 1e-8;
typedef pair<int,int>PII;
vector<PII>star;
int dx[8] = {1, 0, -1, 0, 1, 1, -1, -1};
int dy[8] = {0, 1, 0, -1, 1, -1, 1, -1};
double h[N];
char p[M][M];
bool st[M][M];
char res[M][M];
int m,n,cnt = 0;
char check()
{
double sum = 0;
for(int i = 0;i < star.size() - 1;++i){
for(int j = i + 1;j < star.size(); ++j){
int dx = star[i].first - star[j].first;
int dy = star[i].second - star[j].second;
sum += sqrt(dx * dx + dy * dy);
}
}
for(int i = 1;i <= cnt; ++i){
if(abs(h[i] - sum) < ep) return i + 'a' - 1;
}
cnt ++;
h[cnt] = sum;
return cnt + 'a' - 1;
}
void bfs(int i,int j)
{
st[i][j] = true;
queue<PII>q;
q.push({i,j});
while(q.size() != 0)
{
auto t = q.front();
q.pop();
star.push_back({t.first,t.second});
for(int k = 0;k < 8;++k){
int x = t.first + dx[k];
int y = t.second + dy[k];
if(x < 0||x >= n || y < 0||y >= m||st[x][y]) continue;
if(p[x][y] == '1'){
st[x][y] = true;
q.push({x,y});
}
}
}
return;
}
int main()
{
memset(res,'0',sizeof(res));
cin >> m >> n;
for(int i = 0;i < n; ++i) cin >> p[i];
for(int i = 0;i < n; ++i){
for(int j = 0;j < m;++j){
if(!st[i][j]&&p[i][j] == '1'){
star.clear();
bfs(i,j);
char c = check();
for(auto t:star)
{
res[t.first][t.second] = c;
}
}
}
}
for(int i = 0;i < n; ++i){
for(int j = 0;j < m; ++j){
cout << res[i][j];
}
cout << endl;
}
return 0;
}
2.单调栈
给定一个长度为 N
的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
模板题
#include<iostream>
#include<stack>
using namespace std;
int n;
stack<int>q;
int main(){
cin >> n;
while(n--){
int t;
cin >> t;
while(q.size() != 0 && q.top() >= t) q.pop();
if(q.size() == 0) cout << "-1" << ' ';
else cout << q.top() << ' ';
q.push(t);
}
return 0;
}
3.矩形牛棚
作为一个资本家,农夫约翰希望通过购买更多的奶牛来扩大他的牛奶业务。
因此,他需要找地方建立一个新的牛棚。
约翰购买了一大块土地,这个土地可以看作是一个 R 行(编号 1∼R)C 列(编号 1∼C)的方格矩阵。
不幸的是,他发现其中的部分方格区域已经被破坏了,因此他无法在整个 R×C 的土地上建立牛棚。
经调查,他发现共有 P 个方格内的土地遭到了破坏。
建立的牛棚必须是矩形的,并且内部不能包含被破坏的土地。
请你帮约翰计算,他能建造的最大的牛棚的面积是多少。
单调栈
主要思路:每个题比较考验题目转化模型的能力,h数组的目的和初始化比较难想。
(这个题卡stl,栈只能使用数组模拟)
#include <iostream>
#include <stack>
#include<cstring>
using namespace std;
const int N = 3005;
int p[N][N];
int h[N][N]; // 从i行j列上行完好土地的数量
int r, c, k;
int work(int k) {
int q[N],cnt = 0;
int ll[N], rr[N];
for (int i = 1; i <= c; ++i) {
while (cnt != 0 && h[k][i] <= h[k][q[cnt]]) cnt--;
if (cnt == 0) ll[i] = 0;
else ll[i] = q[cnt];
cnt++;
q[cnt] = i;
}
memset(q,0,sizeof(q));
cnt = 0;
for (int i = c; i >= 1; --i) {
while (cnt != 0 && h[k][i] <= h[k][q[cnt]]) cnt--;
if (cnt == 0) rr[i] = c+1;
else rr[i] = q[cnt];
cnt++;
q[cnt] = i;
}
int ans = 0;
for (int i = 1; i <= c; ++i)
ans = max(ans, (rr[i] - ll[i] - 1) * h[k][i]);
return ans;
}
int main() {
cin >> r >> c >> k;
while (k--) {
int x, y;
cin >> x >> y;
p[x][y] = 1;
}
for (int i = 1; i <= r; ++i) {
for (int j = 1; j <= c; ++j) {
if (p[i][j] != 1) {
h[i][j] = h[i - 1][j] + 1;
}
}
}
int ans = 0;
for (int i = 1; i <= r; ++i) {
ans = max(ans, work(i));
}
cout << ans << endl;
return 0;
}