当前位置:首页 > 牛客 > 牛客网23954题:动态规划解决队列得分

牛客网23954题:动态规划解决队列得分

4个月前 (08-17)

牛客网23954题:动态规划解决队列得分 牛客题解 动态规划算法 C++ 第1张

一、题目解读

本题考察动态规划在集合元素选择问题中的应用。题目给定N个元素,每个元素属于特定集合(set)并具有特定值(value)。要求选择若干元素组成序列,满足相邻元素若属于相同集合则扣除10分,最终目标是获得最高总分并使用最少元素。

二、解题思路

采用动态规划解法,定义dp[i][j]表示前i个元素中以集合j结尾时的最大得分和对应最小长度。通过三种状态转移处理:不选当前元素、选作第一个元素、选作后续元素。特别处理相邻相同集合的扣分情况。

三、解题步骤

1.初始化dp数组为INT_MIN

2.处理第一个元素的初始状态

3.遍历后续元素:

    保持不选当前元素的状态

    作为新序列开头的情况

    作为序列延续的情况(处理集合相同扣分)

4.最终遍历所有集合状态找出最优解

四、完整代码实现

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

struct Element {
    int set;
    int value;
};

int main() {
    int N;
    cin >> N;
    vector<Element> elements(N);
    
    for (int i = 0; i < N; ++i) {
        cin >> elements[i].set >> elements[i].value;
    }
    
    // dp[i][j]表示前i个元素中以set j结尾的最大得分和最小长度
    vector<vector<pair<int, int>>> dp(N, vector<pair<int, int>>(21, {INT_MIN, 0}));
    
    // 初始化第一个元素
    dp[0][elements[0].set] = {elements[0].value, 1};
    
    for (int i = 1; i < N; ++i) {
        int current_set = elements[i].set;
        int current_value = elements[i].value;
        
        // 不选当前元素的情况
        for (int j = 1; j <= 20; ++j) {
            dp[i][j] = dp[i-1][j];
        }
        
        // 选当前元素作为第一个元素
        if (current_value > dp[i][current_set].first) {
            dp[i][current_set] = {current_value, 1};
        } else if (current_value == dp[i][current_set].first) {
            dp[i][current_set].second = min(dp[i][current_set].second, 1);
        }
        
        // 选当前元素作为非第一个元素
        for (int prev_set = 1; prev_set <= 20; ++prev_set) {
            if (dp[i-1][prev_set].first == INT_MIN) continue;
            
            int bonus = (prev_set == current_set) ? 10 : 0;
            int new_score = dp[i-1][prev_set].first + current_value - bonus;
            int new_length = dp[i-1][prev_set].second + 1;
            
            if (new_score > dp[i][current_set].first) {
                dp[i][current_set] = {new_score, new_length};
            } else if (new_score == dp[i][current_set].first) {
                dp[i][current_set].second = min(dp[i][current_set].second, new_length);
            }
        }
    }
    
    // 找出所有可能的最大得分
    int max_score = INT_MIN;
    int min_length = INT_MAX;
    
    for (int j = 1; j <= 20; ++j) {
        if (dp[N-1][j].first > max_score) {
            max_score = dp[N-1][j].first;
            min_length = dp[N-1][j].second;
        } else if (dp[N-1][j].first == max_score) {
            min_length = min(min_length, dp[N-1][j].second);
        }
    }
    
    cout << max_score << " " << min_length << endl;
    return 0;
}

五、总结

本解法通过三维状态设计(元素索引、集合编号、得分/长度)高效解决问题,时间复杂度O(N*20)。关键点在于正确处理三种状态转移和相邻相同集合的扣分逻辑。该解法可应用于类似需要同时优化多个指标的选择问题。

原创内容 转载请注明出处

分享给朋友:

相关文章

力扣933题:队列的妙用:如何高效统计最近请求

力扣933题:队列的妙用:如何高效统计最近请求

题目重解:我们需要设计一个能统计最近3000毫秒内请求次数的系统。每当新的请求到来时,它会带有时间戳t,我们需要返回过去3000毫秒内(包括当前)发生的请求总数。这就像是在时间轴上维护一个滑动窗口,只...

牛客3895题解析:动态规划求解最大子矩阵问题(分治+优化思路详解)

牛客3895题解析:动态规划求解最大子矩阵问题(分治+优化思路详解)

一、题目解读牛客网第3895题要求求解给定二维矩阵中连续子矩阵元素的最大和。题目需处理矩阵中任意范围的子矩形,并返回其元素之和的最大值。该问题属于经典的动态规划扩展题型,需将一维最大子数组思路延伸至二...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

牛客NC67题解:汉诺塔递归算法与解题步骤

牛客NC67题解:汉诺塔递归算法与解题步骤

一、题目解读牛客NC67题要求解决汉诺塔问题,这是一个经典的递归算法题目。题目给定整数n,代表汉诺塔中的盘子数量,需要输出将n个盘子从起始柱移动到目标柱的所有步骤。汉诺塔问题规则为:每次只能移动一个盘...

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

洛谷1656题解:基于Tarjan算法求解割边问题(附代码与详细步骤)

一、题目解读洛谷1656题要求在无向图中找出所有割边(即删除后导致图不连通的边)。题目核心在于判断图的连通性,并识别哪些边是“桥”。需理解图论中的连通分量概念,以及如何通过算法高效定位割边。二、解题思...

洛谷P2190题解:铁路售票系统车厢计算(差分数组+前缀和优化)

洛谷P2190题解:铁路售票系统车厢计算(差分数组+前缀和优化)

一、题目解读洛谷P2190题要求解决铁路售票系统中的车厢数量计算问题。题目给定n个车站和m条订票申请,每条申请包含区间[x,y)及乘客数z。需要计算在不超载的情况下(每节车厢最多36人),满足所有乘客...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。