蓝(准备C++,B组)

准备

阶段一

1.数据结构

2.基础算法:

2.1排序

最佳解决:

#include <bits/stdc++.h>

using namespace std;

#define N 100002

int n;

vector<pair<int, int>> dui; // 使用 pair 来存储使用时间和原始编号

int main() {

    cin >> n;

    dui.resize(n + 1);

    for (int i = 1; i <= n; i++) {

        int x;

        cin >> x;

        dui[i] = {x, i}; 

    }

    // 按照使用时间从小到大排序,如果使用时间相同,则按原始编号从小到大排序

    sort(dui.begin() + 1, dui.end(), [](const pair<int, int>& a, const pair<int, int>& b) {

        if (a.first == b.first) {

            return a.second < b.second;

        }

        return a.first < b.first;

    });

    for (int k = 1; k <= n; k++) {

        cout << dui[k].second << " ";

    }

    return 0;

}

2.1.1快速排序

n个整数,请按照从小到大的顺序排序。

输入格式:

第一行数字n,1<=n<=100000
第二行n个整数,以一个空格分隔

输出格式:

从小到大排序后的数字,以一个空格分隔

输入样例:

5
4 2 1 3 5

输出样例:

1 2 3 4 5

思路

quicksort(int l,int r){

if(l>=r) return ;     //终止条件

int p=jizhun(l,r);       //一定基准,两quick递归

quicksort(l,p-1);

quicksort(p+1,r);

}

代码

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

int n;
vector<int> a;

int ji(int l,int r){
    int i=l;
    int j=r+1;
    while(i<j){
    while(a[++i]<a[l]&&i<=r);
    while(a[--j]>a[l]);
    if(i>=j) break;
    swap(a[j],a[i]);
    }
    swap(a[l],a[j]);
    return j;
}

void quick(int l,int r){
    if(l>=r) return ;
    int id=ji(l,r);
    quick(l,id-1);
    quick(id+1,r);
}

int main(){
    cin>>n;
    a.resize(n);
    for(int i=0;i<n;i++) cin>>a[i];
    quick(0,n-1);
    for(int i=0;i<n;i++) cout<<a[i]<<" ";
    return 0;
}

2.1.2归并排序

已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A0​,A1​,⋯,AN−1​的中位数指A(N−1)/2​的值,即第⌊(N+1)/2⌋个数(A0​为第1个数)。

输入格式:

输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的并集序列的中位数。

输入样例1:

5
1 3 5 7 9
2 3 4 5 6

输出样例1:

4

输入样例2:

6
-100 -10 1 1 1 1
-50 0 2 3 4 5

输出样例2:

1

思路

注意!!!--->这道题合并集合,不做删除,所以合并后数组大小为2n

代码 

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

int n;
vector<int> a;
vector<int> b;

void merge(vector<int>& a,vector<int>& b,int n){
    int i=0,j=0,k=1;
    vector<int> c(3*n);
    while(i<n&&j<n){
        if(a[i]<=b[j]){
            c[k]=a[i];
            k++;
            i++;
        }
        else if(a[i]>b[j]){
            c[k]=b[j];
            k++;
            j++;
        }
    }

    while(i<n){
        c[k]=a[i];
        i++;
        k++;
    }

    while(j<n){
        c[k]=b[j];
        j++;
        k++;
    }
    k--;
    if(k%2!=0) cout<<c[k/2];
    else cout<<(c[k/2]+c[k/2+1])/2;
}

int main(){
    cin>>n;
    a.resize(n);
    b.resize(n);
    for(int i=0;i<n;i++) cin>>a[i];
    for(int j=0;j<n;j++) cin>>b[j];

    merge(a,b,n);
    return 0;
}

2.1.3桶排序

代码

#include <bits/stdc++.h>

using namespace std;

int n;

void buff(vector<int>& a){

  if(a.empty()) return;

  //找最大最小,确认桶数量(由数据范围定)

  int mmax=0;

  int mmin=500005;

  for(int i=0;i<n;i++){

    mmax=mmax>a[i]?mmax:a[i];

    mmin=mmin<a[i]?mmin:a[i];

  }

  int num=mmax-mmin+1;

  vector<vector<int>> tong(num);

  //分配

  for(int j=0;j<n;j++){

    int id=a[j]-mmin;

    tong[id].push_back(a[j]);

  }

  //排序

  for(int k=0;k<num;k++){

    sort(tong[k].begin(),tong[k].end());

  }

  //合并

  int index = 0;

    for (int o=0;o<num;o++) {

        for (int x : tong[o]) {

            a[index++] =x;

        }

    }

}

int main()

{

  cin>>n;

  vector<int> arr;

  arr.resize(n);

  for(int i=0;i<n;i++){

    cin>>arr[i];

  }

  buff(arr);

  for(int j=0;j<n;j++) cout<<arr[j]<<" ";

  return 0;

}

2.1.4总结

1. 快速排序(Quick Sort)

快速排序通过选择一个基准元素,将数组分为两部分,然后递归地对这两部分进行排序。

定基准,两quick;

quick(int left,int right){

if(l>=r) return; //结束条件

int p=ji(int l,int r);

quick(l,p);

quick(p+1,r);

}

定基准:

int ji(int l,int r){
    int i=l;
    int j=r+1;
    while(i<j){
    while(a[++i]<a[l]&&i<=r);
    while(a[--j]>a[l]);
    if(i>=j) break;
    swap(a[j],a[i]);
    }
    swap(a[l],a[j]);
    return j;
}

2.归并排序

归并排序通过将数组分成两半,分别排序,然后将两个有序数组合并。

mid对半,两个sort+merge

void merge(vector<int>& arr, int left, int mid, int right) {
    vector<int> temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;

    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }

    while (i <= mid) temp[k++] = arr[i++];
    while (j <= right) temp[k++] = arr[j++];

    for (int p = 0; p < k; p++) {
        arr[left + p] = temp[p];
    }
}

void mergeSort(vector<int>& arr, int left, int right) {
    if (left >= right) return; // 递归终止条件

    int mid = (left + right) / 2;
    mergeSort(arr, left, mid);  // 排序左半部分
    mergeSort(arr, mid + 1, right); // 排序右半部分
    merge(arr, left, mid, right); // 合并两部分
}

3. 桶排序(Bucket Sort)

桶排序将元素分配到多个桶中,每个桶单独排序,最后合并所有桶。


void bucketSort(vector<float>& arr) {


    vector<vector<float>> buckets(num); // 创建n个桶

桶的分配:

  • 我们根据数组中的最大值和最小值确定桶的数量。

  • 每个桶的索引通过 num - minVal 计算得到,确保每个元素都能正确分配到桶中

    // 将元素分配到桶中
    for (float num : arr) {
        int bucketIndex = num-minVal;
        buckets[bucketIndex].push_back(num);
    }

    // 对每个桶进行排序
    for (auto& bucket : buckets) {
        sort(bucket.begin(), bucket.end());
    }

    // 合并所有桶
    int index = 0;
    for (auto& bucket : buckets) {
        for (float num : bucket) {
            arr[index++] = num;
        }
    }
}

2.2二分查找

代码:

#include <bits/stdc++.h>

using namespace std;

int n,k;

int maxs=0;

vector<pair<int,int>> cady;
 

bool check(int mid){

  long long sum = 0;

    for (int i = 0; i < n; i++) {

        int h = cady[i].first;

        int w = cady[i].second;

        sum += (long long)(h / mid) * (w / mid); // 计算可以切出多少个边长为 mid 的正方形

        if (sum >= k) { 

            return true;

        }

    }

    return false;

}

int find(int l,int r){

  int result = 0;

    while (l <= r) {

        int mid = (l+r)/2; 

        if (check(mid)) {

            result = mid; 

            l = mid + 1; 

        } else {

            r = mid - 1; 

        }

    }

    return result;

}

int main()

{

  cin>>n>>k;

  cady.resize(n);

  for(int i=0;i<n;i++){

    cin>>cady[i].first>>cady[i].second;

    int s=min(cady[i].first,cady[i].second);

    maxs=maxs>s?maxs:s;

  }

  cout<<find(1,maxs);

  return 0;

}

2.3.BFS/DFS

2.3.1BFS

BFS介绍:

BFS通常使用队列(Queue)数据结构来实现。队列是一种先进先出(FIFO)的数据结构,非常适合用于逐层扩展搜索范围。具体实现步骤如下:

  1. 创建一个队列,并将起始节点入队。

  2. 标记起始节点为已访问。

  3. 当队列不为空时,执行以下步骤:

    • 从队列中取出一个节点,作为当前节点。
    • 遍历当前节点的所有邻居节点。
    • 如果某个邻居节点尚未被访问,则将其加入队列,并标记为已访问。
  4. 应用场景

    BFS因其独特的遍历方式,在计算机科学中得到了广泛的应用,包括但不限于以下几个方面:

  5. 最短路径问题:在无权图中,BFS可以用于找到从起点到终点的最短路径。例如,在迷宫问题中,BFS可以帮助找到从入口到出口的最短路径。

  6. 连通性问题:BFS可以用于判断图中的两个节点是否连通。通过从任意节点开始进行BFS遍历,如果能够访问到目标节点,则说明两个节点是连通的;否则,它们是不连通的。

  7. 拓扑排序问题:BFS可以用于对有向无环图(DAG)进行拓扑排序。拓扑排序是一种对有向图进行线性排序的方法,使得对于每一条有向边 (u, v),顶点 u 在排序结果中都出现在顶点 v 之前。

  8. 图的遍历:BFS可以用于遍历图中的所有节点,确保每个节点都被访问一次。

1.走迷宫(BFS)

代码:

2.七步诗

代码:

#include <bits/stdc++.h>

using namespace std;

const int dx[8] = {1, 2, 2, 1, -1, -2, -2, -1};

const int dy[8] = {2, 1, -1, -2, -2, -1, 1, 2};

int main() {

    int n, m;

    cin >> n >> m;

    vector<vector<char>> grid(n, vector<char>(m));

    pair<int, int> start;

    for (int i = 0; i < n; ++i) {

        for (int j = 0; j < m; ++j) {

            cin >> grid[i][j];

            if (grid[i][j] == 'S') {

                start = {i, j};

            }

        }

    }

    queue<pair<int, int>> q;

    q.push(start);

    vector<vector<bool>> visited(n, vector<bool>(m, false));

    visited[start.first][start.second] = true;

    int maxBeans = 0;

    while (!q.empty()) {

        auto current = q.front();

        q.pop();

        int x = current.first;

        int y = current.second;

        if (grid[x][y] == 'b') {

            maxBeans++;

        }

       for (int i = 0; i < 8; ++i) {

            int nx = x + dx[i];

            int ny = y + dy[i];

            if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny] && grid[nx][ny] != 'x') {

                visited[nx][ny] = true;

                q.push({nx, ny});

            }

        }

    }

    cout << maxBeans << endl;

    return 0;

}

2.3.2.DFS

1.排列问题

 解释:

代码的逻辑问题

  1. a[x]++ 的作用

    • 统计每个数字 x 出现的次数。

    • 但代码中 a[x] 的值可能为 0(如果 x 没有出现过),这会导致后续的累乘结果为 0。

  2. res *= a[i] 的作用

    • 如果某个 a[i] 为 0,则 res 会变为 0,且后续的 res 也会保持为 0。

    • 这意味着一旦某个数字 i 没有出现过,res 就会变为 0,且 ans 不会再增加。

  3. ans += res 的作用

    • 将当前的 res 累加到 ans 上。

    • 由于 res 可能会变为 0,ans 的值会在某个点停止增长。


代码的实际功能

这段代码的目的是计算某种排列的数量,具体逻辑如下:

  • 统计每个数字 x 在 [1, n] 范围内出现的次数。

  • 通过累乘 a[i] 的值,计算某种排列的数量。

  • 如果某个数字 i 没有出现过(即 a[i] == 0),则排列数量为 0。

2.简单数组操作

代码:

#include <bits/stdc++.h>

using namespace std;

int n, a, b;

vector<int> gra;

int mmin = 1e9;

void dfs(int t) {

    if (t >= mmin) return; // 剪枝

    bool flag = true;

    for (int i = 1; i <= n; i++) {

        if (gra[i] >= 0) {

            flag = false;

            break;

        }

    }

    if (flag) {

        mmin = min(mmin, t);

        return;

    }

    for (int i = 2; i <= n - 1; i++) {

        if (gra[i - 1] >= 0 || gra[i] >= 0 || gra[i + 1] >= 0) {

            gra[i - 1] -= b, gra[i] -= a, gra[i + 1] -= b;

            dfs(t + 1);

            gra[i - 1] += b, gra[i] += a, gra[i + 1] += b;

        }

    }

}

int main() {

    cin >> n >> a >> b;

    gra.resize(n + 1);

    for (int i = 1; i <= n; i++) cin >> gra[i];

    int sum = 0;

    while (gra[1] >= 0) {

        gra[1] -= b, gra[2] -= a, gra[3] -= b;

        sum++;

    }

  while (gra[n] >= 0) {

        gra[n] -= b, gra[n - 1] -= a, gra[n - 2] -= b;

        sum++;

    }

    dfs(sum);

    cout << mmin;

    return 0;

}

3.动态规划

3.1背包问题

3.1.1 0-1背包

(每个物品只使用一次)

动态方程:  dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);  //选

dp[i][j]=dp[i-1][j]; //不选

3.1.1.1 小背包

代码:

#include <bits/stdc++.h>

using namespace std;

#define N 1001

int n, m;

int w[N], v[N];

int dp[N][N] = {0}; 

int main() {

    cin >> n >> m;

    for (int i = 1; i <= n; i++) {

        cin >> v[i] >> w[i];

    }

    for (int j = 1; j <= n; j++) {

        for (int k = 0; k <= m; k++) {

            if (v[j] <= k) {

                dp[j][k] = max(dp[j-1][k], dp[j-1][k-v[j]] + w[j]); 

            } else {

                dp[j][k] = dp[j-1][k]; 

            }

        }

    }

    cout << dp[n][m];

    return 0;

}

解析:

这是动态规划表,列标签有点错位,自己脑部挪一下。

k=0k=1k=2k=3k=4k=5
j=0000000
j=1022222
j=2024666
j=3024668
j=4024668

简单解析一下:初始化全部为0,0件物品是所有价值为0。

装入第一件物品,当未达到足够容量时,等于同容量装入前一件的价值,如果能装时--》考虑:

装:未装入该物品前的价值+装入物品的价值。

不装:及同容量上一件物品的价值。

3.1.2 完全背包

某个物品可以使用无限次;

动态方程:

dp[j][k]=max(dp[j-1][k],value[j]+dp[j][k-weight[j]]);  //可以放

  dp[j][k]=dp[j-1][k];  //不可以放

3.1.2.1 大背包

代码:

#include <bits/stdc++.h>

using namespace std;

#define N 1002

int n,m;

int dp[N][N]={0};

int value[N],weight[N];

int main() 

{

  cin>>n>>m;

  for(int i=1;i<=n;i++){

    cin>>weight[i]>>value[i];

  }

  for(int j=1;j<=n;j++){

    for(int k=0;k<=m;k++){

      if(weight[j]<=k) dp[j][k]=max(dp[j-1][k],value[j]+dp[j][k-weight[j]]);

      else dp[j][k]=dp[j-1][k];

    }

  }

  cout<<dp[n][m];

  return 0;

}

3.1.3  未知背包
3.1.3.1 购物策略

代码:

#include<bits/stdc++.h>

using namespace std;

using ll = long long;

ll dp[4010];

ll c[2010],t[2010];

int main()

{

  int n;cin>>n;

  ll v =0;

  for(int i=1;i<=n;i++)

  {

    cin>>t[i]>>c[i];

    t[i]++;

    v=max(v,t[i]);

  }

  v+=n;

  for(int i=1;i<=v;i++) dp[i]=1e18;

  for(int i=1;i<=n;i++)

  {

    for(int j=v;j>=t[i];j--)

    {

      dp[j]=min(dp[j],dp[j-t[i]]+c[i]);

    }

  }

  ll ans = 1e18;

  for(int i=n;i<=v;i++)

  {

    ans=min(ans,dp[i]);

  }

  cout<<ans<<endl;

  return 0;

3.1.3.2

4.贪心

4.1 滑动窗口

代码: 

#include<cstdio>

#include<algorithm>

using namespace std;

int n,d,k;

int nowlike[100005];

struct node{

    int ts;

    int id;

};

node arr[100005];

bool ishot[100005];

bool cmp(node x,node y)

{

    return x.ts<y.ts;

}

int main()

{

    scanf("%d%d%d",&n,&d,&k);

    for(int i=1;i<=n;i++)

        scanf("%d%d",&arr[i].ts,&arr[i].id);

    sort(arr+1,arr+1+n,cmp);

    int l = 1;

    for(int i=1;i<=n;i++)

    {  

            nowlike[arr[i].id]++;

        while(arr[i].ts >= arr[l].ts + d) nowlike[arr[l++].id]--;     // 移动窗口左边界,确保窗口内的时间跨度不超过d

        if(nowlike[arr[i].id]>=k) ishot[arr[i].id] = true;

    }

    for(int i=0;i<=100005;i++)

        if(ishot[i])

            printf("%d\n",i);

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值