蓝桥杯C++大学B组一个月冲刺记录2024/3/22

蓝桥杯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;
}

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值