当青训营遇上码上掘金
主题3 寻友之旅
题目概述
A和B分别在节点N和K(0 <= N,K <= 10000),A要去找B,A每分钟可以从任意节点X移动到X-1,X+1,2X,求A找到B需要的最短时间
题目分析
从题目描述不难看出这是一道图论题,图论题的常见考察算法为搜索,动态规划,最短路,二分图,网络流等等。本题可以使用的算法为广度优先搜索和堆优化的dijkstra。
解题思路
解法1 搜索
对于每一个节点i,向i+1,i-1,2i建边,建边可以用vector进行维护,然后从节点N开始进行广度优先搜索,广搜用队列进行维护,期间用数组dis[i]来保存节点N到每一个节点需要的最少时间,当搜到K时马上停止搜索,并输出答案dis[K]
解法2 堆优化的dijkstra
建边方式和解法1相同,从节点N开始跑dijkstra最短路,每次从小根堆中取出堆顶的元素(也就是目前未被访问过的距离N最近的节点的编号和距离值),用它来对与它相邻的节点进行松弛操作,再把那些被松弛过且没有出现在优先队列里的节点放入队列中,如此反复,直到队列为空,最后输出答案dis[K]即可。
代码实现
#include <bits/stdc++.h>
using namespace std;
struct node {
int pos,val;
friend bool operator <(node x,node y) {
return x.val > y.val;
}
node (int a,int b) {
pos = a,val = b;
}
};
vector <int> v[100005];
int s,t;
int dis[100005];
bool on_queue[100005];
priority_queue <node> pq;
void dijkstra(int s)
{
memset(dis,0x3f,sizeof(dis));
dis[s] = 0;
pq.push(node(s,0));
while (!pq.empty())
{
int x = pq.top().pos;
pq.pop();
on_queue[x] = false;
for (int i = 0;i < v[x].size(); i++)
{
int next = v[x][i];
if (dis[next] > dis[x] + 1)
{
dis[next] = dis[x] + 1;
if (!on_queue[next])
{
on_queue[next] = true;
pq.push(node(next,dis[next]));
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
for (int i = 0;i <= 100000; i++)
{
if (i > 0) v[i].push_back(i - 1);
if (i < 100000) v[i].push_back(i + 1);
if (2 * i <= 100000) v[i].push_back(2 * i);
}
cin >> s >> t;
dijkstra(s);
cout << dis[t] << endl;
}
主题4 攒青豆
题目分析
考虑中间每一根柱子能接到多少青豆。令dp1[i]表示1-i柱子的高度的最大值,dp2[i]为i-n柱子高度的最大值,ans[i]为第i根柱子能接到的青豆数,则有:
ans[i] = max(0,min(dp1[i-1],dp2[i+1))-height[i]) (1 < i < n)
代码实现
#include <bits/stdc++.h>
#define llt long long
using namespace std;
stack <int> s;
int n;
llt ans;
int h[100005],dp1[100005],dp2[100005];
int main()
{
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1;i <= n; i++)
{
cin >> h[i];
dp1[i] = max(dp1[i - 1],h[i]);
}
for (int i = n;i >= 1; i--)
{
dp2[i] = max(dp2[i + 1],h[i]);
}
for (int i = 2;i < n; i++)
{
int t = min(dp1[i - 1],dp2[i + 1]);
ans += max(0,t - h[i]);
}
cout << ans << endl;
}