UVALive - 4327 Parade DP + 优先队列

题目大意:有n+1条横线,m+1条竖线,你的任务是从最南边的路走到最北边的路,使得走过的路上的高兴值和最大。同一段路不能走超过两次,且不能从北往南走,另外每条横向路上所花的时间不能超过k

解题思路:设dp[i][j]为走到第i条横线,第j条竖线的十字路口的高兴值的最大值
则dp[i][j] = max(dp[i][j], dp[i-1][k] + sum_value[j-1]-sum_value[j][k-1])
然后从左到右扫描更新,再从右到左扫描更新

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 110
#define maxm 10010
#define INF 0x3f3f3f3f
int sum_len[maxn][maxm], sum_value[maxn][maxm], q[maxm], dp[maxn][maxm], n, m, k;
void DP() {
    int front, rear;
    for(int i = 1; i <= n; i++) {
        front = rear = 0;
        q[0] = 1;
        for(int j = 1; j <= (m+1); j++) {
            while(front <= rear && dp[i-1][q[rear]] - sum_value[i][q[rear]-1] <= dp[i-1][j] - sum_value[i][j-1])
                rear--;
            q[++rear] = j;

            while(front <= rear && sum_len[i][j-1] - sum_len[i][q[front]-1] > k)
                front++;
            dp[i][j] = dp[i-1][q[front]] + sum_value[i][j-1] - sum_value[i][q[front]-1];
        }

        front = rear = 0;
        q[0] = m + 1;
        for(int j = m+1; j >= 1; j--) {
            while(front <= rear && dp[i-1][q[rear]] + sum_value[i][q[rear]-1] <= dp[i-1][j] + sum_value[i][j-1])
                rear--;
            q[++rear] = j;
            while(front <= rear && sum_len[i][q[front]-1] - sum_len[i][j-1] > k)
                front++;
            dp[i][j] = max(dp[i][j],dp[i-1][q[front]] + sum_value[i][q[front]-1]-sum_value[i][j-1]);
        }
    }
}

int main() {
    while(scanf("%d%d%d", &n, &m, &k) == 3 && (n+m+k)) {
        n++;
        int tmp;
        for(int i = 1; i <= n; i++) { sum_value[i][0] = 0; for(int j = 1; j <= m; j++) {
                scanf("%d", &tmp);
                sum_value[i][j] = sum_value[i][j-1] + tmp;
            }
        }

        for(int i = 1; i <= n; i++) {
            sum_len[i][0] = 0;
            for(int j = 1; j <= m; j++) {
                scanf("%d",&tmp);
                sum_len[i][j] = sum_len[i][j-1] + tmp;  
            }
        }
        for(int i = 1; i <= (m+1); i++)
            dp[0][i] =  0;
        DP();
        int ans = -INF;
        for(int i = 1; i <= (m+1); i++)
            ans = max(ans,dp[n][i]);
        printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值