思路 动态规划
一开始用刚学会的回溯算法做,运行超时。改用动态规划,听了yxc的讲解,目前一知半解,好像省了很多步骤。第一次做这种题,先记住模型好思路,以后再战。
题目最后得到的结果是一个类似于一个单调上升函数(是一连串的点,应该不算函数),x轴是年龄,y轴是分数。设分数从小到大,年龄也是从小到大,构成的点是对应x、y轴的球员。
现在先把y轴的分数排列好,这时x轴是无序的。而最终结果一定是上升序列,因此只要任选x轴的点满足Xm >= Xn(m > n,m、n是标号)即可。再在所有的选择中选出最大值即为答案。DFS应该还是超时,思路继续往动态规划上面靠。
闫氏DP分析法:
状态表示:dp[i]:
- 集合:包含第i个数的上升序列集合。
- 属性:MAX
状态划分:
对dp[i]进行划分。如果要得到包含第i个数的上升序列,可以先划分为两大部分:1.只有第i个数 2. 不只包含第i个数。 再对第二部分进行细化,就是把前面的所有上升序列和i做拼接。前面的上升序列即为包含k的上升序列(0 < k < i),得到
状态转移方程:
dp[i] = scores[i];
dp[i] = max(dp[i], dp[k] + scores[i])(0 < k < i)
为什么必须排序后才能做呢?回到状态转移方程,i与上升子序列拼接是有条件的。如果没有排序,判断条件没法写。动态规划只能得到某一状态的最优解,求不出路径。按照不排序的思路仔细写一下,就会发现i必须要与整个路径进行判断,因为得不到路径判断条件也就无从写起。
排序之后呢?如果i要拼接到包含k的上升序列,只和k判断即可,因为包含k点的路径已经“排序”好了,i如果通过了和k的条件判断,k之前的点的条件判断也能通过。
class Solution {
public:
static bool comp (const pair<int, int> a, const pair<int, int> b) {
return a.first < b.first;
}
int bestTeamScore(vector<int>& scores, vector<int>& ages) {
int n = scores.size();
vector<int> dp(n);
vector<pair<int, int>> people(n);
for (int i = 0; i < n; i ++) people[i] = {scores[i], ages[i]};
sort(people.begin(), people.end());
int res = 0;
for (int i = 0; i < n; i ++) {
dp[i] = people[i].first;
for (int j = 0; j < i; j ++)
if (people[i].second >= people[j].second)
dp[i] = max(dp[j] + people[i].first, dp[i]);
if (dp[i] > res) res = dp[i];
}
return res;
}
};