华为 9.21 9月21日 机试 第三题 动态规划 简单解法
思路:
根据坐标进行dp递推而不是根据树的编号,这是关键。
dp[i]代表第i个坐标之前,最大的价值(只考虑树的左右边界全包含在坐标i之前的树)。
坐标从第一棵树的右边往后移动,每新包含一棵树,进行一次判断:
1、新树的价值(value)小于覆盖范围内其他树的价值(dp[右边界 - 1] - dp[左边界]),则不种植该树。
2、新树的价值(value)大于覆盖范围内其他树的价值(dp[右边界 - 1] - dp[左边界]),则移除其他树,种植这棵新树,更新dp[右边界]。
i移到最后时,dp[终点]就是最优种植方案的价值。
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
bool fun(vector<int> &a,vector<int> &b){
if(a[0] < b[0] ) return true;
return false;
}
int main() {
//输入处理
int n;
cin >> n;
if( n <= 0 ){
cout << 0;
return 0;
}
//len记录所有树的右边界能覆盖的最远的距离
int len = 0;
vector<vector<int>> data(n + 1 ,vector<int>(3,-1));
for(int i = 1 ; i < n + 1 ; i ++ ){
cin >> data[i][0];
}
for(int i = 1 ; i < n + 1 ; i ++ ){
cin >> data[i][1];
//最大坐标是覆盖最远的那棵树的右边界,注意,不一定是越靠后的树覆盖越远
len = max( len , data[i][0] + data[i][1]);
}
for(int i = 1 ; i < n + 1 ; i ++ ){
cin >> data[i][2];
}
//按每棵树适合种植的位置排序
sort(++data.begin(),data.end(),fun);
//dp[i]代表第i个坐标之前,最大的价值(只考虑树的范围全包含在坐标i之前的树)
vector<int> dp( len + 1,0);
//计算第i个坐标之前,最大的价值
for(int i = data[1][0] + 1 ; i < len + 1 ; i ++ ){
for( int j = 1 ; j < n + 1 && data[j][0] < i ; j ++ ){
//向后移动坐标i,如果有新的树被包含在i内,则计算这棵树的价值data[j][2]和这棵树范围内所有其他树的价值dp[i - 1] - dp[data[j][0] - data[j][1]]哪个更大,取较大的
if( data[j][0] + data[j][1] == i && data[j][2] > dp[i - 1] - dp[data[j][0] - data[j][1]]){
dp[i] = max( dp[i] , dp[ data[j][0] - data[j][1] ] + data[j][2] );
}
}
//如果dp[i]有更新,则肯定大于dp[i - 1],否则坐标i前所有树的价值等于坐标i-1前所有树的价值
dp[i] = max(dp[i],dp[i - 1]);
}
//最后一个坐标前的所有树的最大价值即为结果
cout << dp[len];
return 0;
}
/*
5
2 3 6 5 7
1 1 3 1 1
20 20 100 70 60
结果150
4
2 3 4 5
1 1 1 2
50 10 40 70
结果120
*/
#华为##华为机试##动态规划#
360集团公司福利 405人发布
查看5道真题和解析