【单调队列优化dp】Uvalive4327丨Poj3926 Parade

本文介绍了一种使用单调队列优化动态规划(DP)的方法,通过实例代码详细解析了如何利用单调队列来减少复杂度,提高算法效率。特别讨论了在路径长度可能超过预设阈值的情况下的解决方案。

uvalive戳这里 poj戳这里


单调队列优化的dp……挺显然的…………

70行代码。。写了得快崩溃。。。debug更是要。。。跪。。。了。。。。

没力气写思路了…………反正和trade那道题也差不多


dp[i][j] = max{dp[i-1][j], dp[i-1][k] + sum[k] - sum[j] / sum[j] - sum[k]}  然后两个单调队列就行了。。

写的肉疼 = =然后WA WA WA WA....

被叉老师查出来的两个问题 ①路可能长于K 不能直接拿最近的更新 ②多组数据所以dp一定要清零。。。。。。


#include <cstdio>
#include <iostream>

using namespace std;

const int Nmax = 105;
const int Mmax = 10005;

int N, M, K;
int w[Nmax][Mmax], t[Nmax][Mmax];
int dp[3][Mmax];

namespace queue {
    int q[Mmax], head, tail;
    
    inline void init() { head = 0, tail = -1; q[0] = 0; }
    inline void push_back(int x) { q[++tail] = x; }
    inline void pop_back() { --tail; }
    inline void pop_front() { ++head; }
    inline int front() { return q[head]; }
    inline int back() { return q[tail]; }
    inline int size() { return tail - head + 1; }
}

int main()
{
    while (~scanf("%d%d%d", &N, &M, &K) && (N || M || K))
    {
        for (int i = 0; i <= N; ++i)
        for (int j = 1; j <= M; ++j)
        {
            scanf("%d", &w[i][j]);
            w[i][j] += w[i][j - 1];
        }
        for (int i = 0; i <= N; ++i)
        for (int j = 1; j <= M; ++j)
        {
            scanf("%d", &t[i][j]);
            t[i][j] += t[i][j - 1];
        }
        
        using namespace queue; memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= N + 1; ++i)
        {
            int nw = i & 1, pr = nw ^ 1;
            
            init(); for (int j = 0; j <= M; ++j)
            {
                while (size() > 0 && t[i - 1][j] - t[i - 1][front()] > K) pop_front();
                dp[nw][j] = !size() ? dp[pr][j] : max(dp[pr][j], dp[pr][front()] + w[i - 1][j] - w[i - 1][front()]);
                while (size() > 0 && dp[pr][back()] - w[i - 1][back()] < dp[pr][j] - w[i - 1][j]) pop_back();
                push_back(j);
            }
            init(); for (int j = M; ~j; --j)
            {
                while (size() > 0 && t[i - 1][front()] - t[i - 1][j] > K) pop_front();
                dp[nw][j] = !size() ? dp[nw][j] : max(dp[nw][j], dp[pr][front()] + w[i - 1][front()] - w[i - 1][j]);
                while (size() > 0 && dp[pr][back()] + w[i - 1][back()] < dp[pr][j] + w[i - 1][j]) pop_back();
                push_back(j);
            }
        }
        int ans = 0;
        for (int i = 0; i <= M; ++i) ans = max(ans, dp[(N & 1) ^ 1][i]);
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值