寻友之旅(BFS),攒青豆(DP)

126 阅读2分钟

当青训营遇上码上掘金

寻友之旅

题目:

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。 步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1 公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走) 请帮助小青通知小码,小青最快到达时间是多久? 输入: 两个整数 N 和 K 输出: 小青到小码家所需的最短时间(以分钟为单位)

解题思路

小青在地点N,小码在地点K,小码位置不动,假设小青当前位置是x,可以进行x+1,x-1,x2的操作。 首先考虑到小青可以进行x+1,x-1,x2的操作,联想到常用的bfs来列举每一步可以走到的位置,开始列举每一步可以到达的位置然后第一次到达K的时间可以直接返回此时所需的最短时间。

实现方法

先初始化所有地点的所需时间为0,dist表示到达当前点所需的最短时间,然后dist[n]是小青当前的位置,也就是所需时间为0,dist[t + 1]是假设当前位置是t,往前走一步,dist[t - 1]是往后走一步, dist[t * 2]是当前位置进行2 * t的操作。

输入格式

输入他们的起始位置 input:

N K

2 6

output:

2

样例解释: 2先走到3再进行2*3到达6。

代码

#!/jcode/lang/cpp https://xitu.github.io/jcode-languages/dist/lang-cpp.json

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int dist[N];
int n, k;
const int INF = 0x3f3f3f3f;

int bfs()
{
    queue<int> q;
    memset(dist, -1, sizeof dist);
    q.push(n);
    dist[n] = 0;
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        if(t == k)
        {
            return dist[t];
        }
        if(t + 1 < N && dist[t + 1] == -1)
        {
            dist[t + 1] = dist[t] + 1;
            q.push(t + 1);
        }
        if(t - 1 >= 0 && dist[t - 1] == -1)
        {
            dist[t - 1] = dist[t] + 1;
            q.push(t - 1);
        }
        if(t * 2 < N && dist[t * 2] == -1)
        {
            dist[t * 2] = dist[t] + 1;
            q.push(t * 2);
        }
    }
    return 0;
}

int main()
{
    scanf("%d%d", &n, &k);
    
    cout << bfs() << endl;
    return 0;
}

攒青豆

题目:

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

image.png

解题思路

通过计算每一个柱子上方可以接到的青豆来累加得出答案,然后左右两边的柱子可以忽略不计,因为他们不可以积累青豆。决定每一竖列可以积累到的数量决定于他左右两边的最高柱子中的最低柱子比如说2这一列(0,1,2,...)就是高度4决定的。

image.png

实现方法

分别求出每一个柱子左右两边的最高柱子,这里使用了DP。

// 左边
  for(int i = 1; i < n; i ++ ) {
      a[i] = max(a[i - 1], height[i - 1]);
  }
  与
// 右边
  for(int i = n - 2; i >= 0; i -- ) {
        b[i] = max(b[i + 1], height[i + 1]);
  }

并累加每一个柱子的绿豆高度即可得出答案

输入格式

输入每一个柱子的高度 input:

5,0,2,1,4,0,1,0,3

output:

17

样例解释:

上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

#!/jcode/lang/cpp https://xitu.github.io/jcode-languages/dist/lang-cpp.json

#include<iostream>
#include<algorithm>
#include<vector>
#include <cstring>
using namespace std;
int main() {
  string t;
  cin >> t;
  vector<int> height;
  int t_size_ = t.size();
  /**
  * 因为未给定height的数组大小,需要用string读取并且进行数据切割得出相应的数据。
  */
  for(int i = 0; i < t_size_; i ++ ) {
    int calc = 0;
    while(i < t_size_ && t[i] >= '0' && t[i] <= '9') {
      calc = calc * 10 + (t[i] - '0');
      i ++ ;
    }
    height.push_back(calc);
  }

  int a[20005] = {0};
  int b[20005] = {0};
  int n = height.size();
  for(int i = 1; i < n; i ++ ) {
      a[i] = max(a[i - 1], height[i - 1]);
  }

  for(int i = n - 2; i >= 0; i -- ) {
        b[i] = max(b[i + 1], height[i + 1]);
  }
  int res = 0;
  for(int i = 1; i < n - 1; i ++ ) {
      if(a[i] > height[i] && b[i] > height[i]) {
          res += min(b[i], a[i]) - height[i];
      }
  }

  cout << res << endl;

  return 0;
}