算法小总结(1)

窗口滑动

Note:这里的窗口滑动并非指的是滑动窗口(即单调队列)问题,而是处理问题的技巧。

题目:来自ABC337的D - Cheating Gomoku Narabe
在这里插入图片描述
链接: ABC337
AC代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
    int h, w, k;
    cin >> h >> w >> k;
    vector<string> s(h);
    for(int i = 0;i < h;i ++){
        cin >> s[i];
    }
    int x, o;
    int ans = k + 1;
    for(int i = 0;i < h;i ++){//每行开始枚举
        x = 0, o = 0; 
        for(int j = 0;j < w;j ++){
            if(s[i][j] == 'o'){
                o ++;
            }
            if(s[i][j] == 'x'){
                x ++;
            }
            if(j >= k - 1 && !x){//中间不能有阻碍
                ans = min(ans, k - o);
            }
            if(j >= k - 1){
                if(s[i][j - k + 1] == 'o'){//窗口开始滑动
                    o --;
                }
                if(s[i][j - k + 1] == 'x'){
                    x --;
                }
            }
        }
    }
    for(int j = 0;j < w;j ++){
        x = 0, o = 0;
        for(int i = 0;i < h;i ++){
            if(s[i][j] == 'o'){
                o ++;
            }
            if(s[i][j] == 'x'){
                x ++;
            }
            if(i >= k - 1 && !x){//中间不能有阻碍
                ans = min(ans, k - o);
            }
            if(i >= k - 1){
                if(s[i - k + 1][j] == 'o'){//窗口开始滑动
                    o --;
                }
                if(s[i - k + 1][j] == 'x'){
                    x --;
                }
            }
        }
    }
    cout << (ans > k ? -1 : ans);
    return 0;
}

重量相同小球找不同最小次数问题

技巧:重量相同的一堆小球中找不同问题,n - 1有几个二进制位就代表至少要几个人,如 n = 10, 则 0 ~ 9 为0000 ~ 1111,说明至少需要4个人,n = 8, 则 0 ~ 7为000 ~ 111,则至少需要3个人。

题目:来自ABC337的E - Bad Juice
在这里插入图片描述
链接: ABC337
AC代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
    int m = 0,p = n - 1;
    while(p){
        m ++;
        p = p >> 1;//(重量相同的一堆小球中找不同问题,n - 1有几个二进制位就代表至少要几个人,如 n = 10, 则 0 ~ 9 为0000 ~ 1111,说明至少需要4个人,n = 8, 则 0 ~ 7为000 ~ 111,则至少需要三个人)
    }
    cout << m << endl;
    //其中第一个人分到的是二进制最后一位为1的juice,第二个人分到的是二进制倒数第二位为1的juice....以此类推·
    vector<vector<int>> a(m + 1);
    for(int i = 1;i <= m;i ++){
        for(int j = 0;j < n;j ++){
            if(j >> (i - 1) & 1){
                a[i].push_back(j);
            }// 用来判断这个数二进制的第几位是什么(是否1)
        }
    }
    for(int i = 1;i <= m;i ++){
        cout << a[i].size() << " ";
        for(auto x : a[i]) cout << x << " ";
        cout << endl;
    }
    string s;
    cin >> s;
    reverse(s.begin(), s.end());
    int sum = 0;
    for(int i = 0;i < (int)s.size();i ++){
        sum += (s[i] - '0') * pow(2 , s.size() - 1 - i);//二进制转化成是十进制
    }
    cout << (sum == 0 ? n : sum) << endl;
    return 0;
}

二维数组和一维数组相互转化问题

解法:假如一维数组的下标是 k, 要转化成n行n列的二维数数组,则x = k / n, y = k % n;
x ,y 的二维数组转化成一维数组,则k = x * n + y;

题目 : 来自acwing- bfs的八数码问题
在这里插入图片描述
链接: 八数码
AC代码:

#include<bits/stdc++.h>
using namespace std;

int bfs(string start){
    string end = "12345678x";
    queue<string> q;
    unordered_map<string, int> d;
    q.push(start);
    d[start] = 0;
    int dx[4] = { 0, -1, 0, 1}, dy[4] = { 1, 0, -1, 0};
    while(!q.empty()){
        auto t = q.front();
        q.pop();
        int distance = d[t];
        if(t == end) return distance;
        int k = t.find('x');//找到x的下标
        int x = k / 3,y = k % 3;//一维数组转化为二维数组
        for(int i = 0;i < 4;i ++){
            int a = x + dx[i],b = y + dy[i];
            if(a >= 0 && a < 3 && b >= 0 && b < 3){
                swap(t[k], t[a * 3 + b]);//将二维数组转化为一位数组
                if(!d.count(t)){
                    d[t] = distance + 1;
                    q.push(t);
                }
                swap(t[k],t[a * 3 + b]);
            }
        }
    }
    return -1;
}

int main(){
    string start;
    for(int i = 0;i < 9;i ++){
        char c;
        cin >> c;
        start += c;
    }
    cout << bfs(start);
    return 0;
}

贪心!区间选点

区间选点问题就是指在几个区间里选出最少的点使得每个区间里面都有点。
在这里插入图片描述
在这里插入图片描述

题目:(模板题)
在这里插入图片描述
模板代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

struct node{
    int l, r;
}a[N];

bool cmp(node b, node c){
    return b.r < c.r;
}

int main(){
    int n;
    cin >> n;
    for(int i = 0;i < n;i ++){
        cin >> a[i].l >> a[i].r;
    }
    sort(a, a + n, cmp);
    int cnt = 1;
    int right = a[0].r;
    for(int i = 1;i < n;i ++){
        if(a[i].l > right){
            right = a[i].r;
            cnt ++;
        }
    }
    cout << cnt;
    return 0;
}

题目:雷达设备
在这里插入图片描述
本题是一个二维的,但本题最关键的点就是把二维问题转化成一维问题
在这里插入图片描述
AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;

struct node{
    double l, r;
}a[N];

bool cmp(node b, node c){
    return b.r < c.r;  
}

int main(){
    int n, d;
    cin >> n >> d;
    for(int i = 0;i < n;i ++){
        double x, y;
        cin >> x >> y;
        if(y > d){
            cout << -1 << endl;
            return 0;
        }else{
           double len = sqrt(d * d - y * y);
           a[i].l = x - len;
           a[i].r = x + len;
        }
    }
    sort(a, a + n, cmp);
    int cnt = 1;
    double right = a[0].r;
    for(int i = 1;i < n;i ++){
        if(a[i].l > right){
            right = a[i].r;
            cnt ++;
        }
    }
    cout << cnt;
    return 0;
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值