一、洛谷P1119 灾后重建
(1)问题描述
题目背景
B 地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。
题目描述
给出 B 地区的村庄数 NN,村庄编号从 00 到 N-1N−1,和所有 MM 条公路的长度,公路是双向的。并给出第 ii 个村庄重建完成的时间 t_iti,你可以认为是同时开始重建并在第 t_iti 天重建完成,并且在当天即可通车。若 t_iti 为 00 则说明地震未对此地区造成损坏,一开始就可以通车。之后有 QQ 个询问 (x,y,t)(x,y,t),对于每个询问你要回答在第 tt 天,从村庄 xx 到村庄 yy 的最短路径长度为多少。如果无法找到从 xx 村庄到 yy 村庄的路径,经过若干个已重建完成的村庄,或者村庄 xx 或村庄 yy 在第 tt 天仍未重建完成,则需要返回 -1
。
输入格式
第一行包含两个正整数N,MN,M,表示了村庄的数目与公路的数量。
第二行包含NN个非负整数t_0, t_1,…, t_{N-1}t0,t1,…,tN−1,表示了每个村庄重建完成的时间,数据保证了t_0 ≤ t_1 ≤ … ≤ t_{N-1}t0≤t1≤…≤tN−1。
接下来MM行,每行33个非负整数i, j, wi,j,w,ww为不超过1000010000的正整数,表示了有一条连接村庄ii与村庄jj的道路,长度为ww,保证i≠ji=j,且对于任意一对村庄只会存在一条道路。
接下来一行也就是M+3M+3行包含一个正整数QQ,表示QQ个询问。
接下来QQ行,每行33个非负整数x, y, tx,y,t,询问在第tt天,从村庄xx到村庄yy的最短路径长度为多少,数据保证了tt是不下降的。
输出格式
共QQ行,对每一个询问(x, y, t)(x,y,t)输出对应的答案,即在第tt天,从村庄xx到村庄yy的最短路径长度为多少。如果在第t天无法找到从xx村庄到yy村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄yy在第tt天仍未修复完成,则输出-1−1。
输入输出样例
输入 #1复制
4 5 1 2 3 4 0 2 1 2 3 1 3 1 2 2 1 4 0 3 5 4 2 0 2 0 1 2 0 1 3 0 1 4
输出 #1复制
-1 -1 5 4
说明/提示
对于30\%30%的数据,有N≤50N≤50;
对于30\%30%的数据,有t_i= 0ti=0,其中有20\%20%的数据有t_i = 0ti=0且N>50N>50;
对于50\%50%的数据,有Q≤100Q≤100;
对于100\%100%的数据,有N≤200N≤200,M≤N \times (N-1)/2M≤N×(N−1)/2,Q≤50000Q≤50000,所有输入数据涉及整数均不超过100000100000。
(2)代码实现
#include<iostream>
#include<cstdio>
#define N 205
using namespace std;
int n,m;
int a[N];
int f[N][N];
inline void updata(int k){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(f[i][j]>f[i][k]+f[j][k])
f[i][j]=f[j][i]=f[i][k]+f[j][k];
return;
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
scanf("%d",a+i);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
f[i][j]=1e9;
}
for(int i=0;i<n;i++)
f[i][i]=0;
int s1,s2,s3;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&s1,&s2,&s3);
f[s1][s2]=f[s2][s1]=s3;
}
int q;
cin>>q;
int now=0;
for(int i=1;i<=q;i++){
scanf("%d%d%d",&s1,&s2,&s3);
while(a[now]<=s3&&now<n){
updata(now);
now++;
}
if(a[s1]>s3||a[s2]>s3)cout<<-1<<endl;
else {
if(f[s1][s2]==1e9)cout<<-1<<endl;
else cout<<f[s1][s2]<<endl;
}
}
return 0;
}
二、LeetCode: 42. 接雨水
(1)问题描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
提示:
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
(2)代码实现
class Solution {
public int trap(int[] height) {
int n=height.length;
if(n==0) return 0;
int[] leftMax=new int[n];
leftMax[0]=height[0];
for(int i=1;i<n;i++){
leftMax[i]=Math.max(height[i],leftMax[i-1]);
}
int[] rightMax=new int[n];
rightMax[n-1]=height[n-1];
for(int i=n-2;i>=0;i--){
rightMax[i]=Math.max(rightMax[i+1],height[i]);
}
int ans=0;
for(int i=0;i<n;i++){
ans+=Math.min(leftMax[i],rightMax[i])-height[i];
}
return ans;
}
}
三、LeetCode: 2091. 从数组中移除最大值和最小值
(1)问题描述
给你一个下标从 0 开始的数组 nums ,数组由若干 互不相同 的整数组成。
nums 中有一个值最小的元素和一个值最大的元素。分别称为 最小值 和 最大值 。你的目标是从数组中移除这两个元素。
一次 删除 操作定义为从数组的 前面 移除一个元素或从数组的 后面 移除一个元素。
返回将数组中最小值和最大值 都 移除需要的最小删除次数。
示例 1:
输入:nums = [2,10,7,5,4,1,8,6]
输出:5
解释:
数组中的最小元素是 nums[5] ,值为 1 。
数组中的最大元素是 nums[1] ,值为 10 。
将最大值和最小值都移除需要从数组前面移除 2 个元素,从数组后面移除 3 个元素。
结果是 2 + 3 = 5 ,这是所有可能情况中的最小删除次数。
示例 2:
输入:nums = [0,-4,19,1,8,-2,-3,5]
输出:3
解释:
数组中的最小元素是 nums[1] ,值为 -4 。
数组中的最大元素是 nums[2] ,值为 19 。
将最大值和最小值都移除需要从数组前面移除 3 个元素。
结果是 3 ,这是所有可能情况中的最小删除次数。
示例 3:
输入:nums = [101]
输出:1
解释:
数组中只有这一个元素,那么它既是数组中的最小值又是数组中的最大值。
移除它只需要 1 次删除操作。
提示:
1 <= nums.length <= 105
-105 <= nums[i] <= 105
nums 中的整数 互不相同
(2)代码实现
class Solution {
public int minimumDeletions(int[] nums) {
int maxIdx=0,minIdx=0;
for(int i=0;i<nums.length;i++){
maxIdx=nums[i]>nums[maxIdx]? i:maxIdx;
minIdx=nums[i]<nums[minIdx]? i:minIdx;
}
int front=Math.max(maxIdx,minIdx)+1;
int back=Math.max(nums.length-maxIdx,nums.length-minIdx);
int f_b=(Math.min(maxIdx,minIdx)+1)+(nums.length-Math.max(maxIdx,minIdx));
return Math.min(Math.min(front, back), f_b);
}
}