HDU-4347-One hundred layer-dp-单调队列优化

博客围绕HDU-4347题目展开,涉及动态规划(dp)和单调队列优化。包含题目描述、输入输出要求、示例以及问题描述,还给出了解题方案和代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU-4347-One hundred layer-dp-单调队列优化

【Description】

Now there is a game called the new man down 100th floor. The rules of this game is:
   1.  At first you are at the 1st floor. And the floor moves up. Of course you 
can choose which part you will stay in the first time.
   2.  Every floor is divided into M parts. You can only walk in a direction (left
or right). And you can jump to the next floor in any part, however if you are now
in part “y”, you can only jump to part “y” in the next floor! (1<=y<=M)
   3.  There are jags on the ceils, so you can only move at most T parts each floor.
   4.  Each part has a score. And the score is the sum of the parts’ score sum you
passed by.
Now we want to know after you get the 100th floor, what’s the highest score you can
get. 

【Input】

The first line of each case has four integer N, M, X, T(1<=N<=100, 1<=M<=10000, 
1<=X, T<=M). N indicates the number of layers; M indicates the number of parts. At 
first you are in the X-th part. You can move at most T parts in every floor in only 
one direction.
Followed N lines, each line has M integers indicating the score. (-500<=score<=500)

【Output】

Output the highest score you can get.

【Examples】

Sample Input

3 3 2 1
7 8 1 
4 5 6 
1 2 3 

Sample Output

29

【Problem Description】

给你一个n*m的矩阵,从第一行第x列开始走,一直到最后一行,求所经过格子的值的和的最大值。
1、同一列只能选择一个方向,向左或右。
2、同一列走的最大距离不超过t
样例的路径:
8->7->4->5->2->3

【Solution】

dp,单调队列优化
定义dp数组dp[i][j],表示到第i行,第j列所能获得最大值。
则dp[i][j]=max(dp[i][j],dp[i-1][k]-sum[i][k-1]+sum[i][j])向右走
  dp[i][j]=max(dp[i][j],dp[i-1][k]+sum[i][k]-sum[i][j-1])向左走
剩下的就是单调队列模板了...

【Code】

/*
 * @Author: Simon 
 * @Date: 2018-08-30 14:15:55 
 * @Last Modified by: Simon
 * @Last Modified time: 2018-08-30 16:36:57
 */
#include<bits/stdc++.h>
using namespace std;
typedef int Int;
#define int long long
#define INF 0x3f3f3f3f
#define maxn 105
#define maxm 10005
int a[maxn][maxm];
int dp[maxn][maxm];
int sum[maxn][maxm];
int n, m, x, t;
int head,tail;
struct node
{
    int val,k;
}q[maxm*2];
void right(int i,int j)
{
    while(head<tail&&dp[i-1][j]-sum[i][j-1]>=q[tail-1].val) tail--;//dp[i-1][k]-sum[i][k]
    q[tail].val=dp[i-1][j]-sum[i][j-1];
    q[tail++].k=j;
    while(head==-1||(head<tail&&j-q[head].k>t)) head++;//保证步数不大于限制条件
    dp[i][j]=max(dp[i][j],q[head].val+sum[i][j]);//dp[i][j]=max(dp[i][j],dp[i-1][k]-sum[i][k-1]+sum[i][j])
}
void left(int i,int j)
{
    while(head<tail&&dp[i-1][j]+sum[i][j]>=q[tail-1].val) tail--;//dp[i-1][k]+sum[i][k];
    q[tail].val=dp[i-1][j]+sum[i][j];
    q[tail++].k=j;
    while(head==-1||(head<tail&&q[head].k-j>t)) head++;//保证步数不大于限制条件
    dp[i][j]=max(dp[i][j],q[head].val-sum[i][j-1]);//dp[i][j]=max(dp[i][j],dp[i-1][k]+sum[i][k]-sum[i][j-1])
}
void solve()
{
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) dp[i][j]=-INF;
    for(int i=1;i<=m;i++)//第一行初始化
    {
        if(abs(x-i)>t) continue;
        if(i<=x) dp[1][i]=sum[1][x]-sum[1][i-1];
        else dp[1][i]=sum[1][i]-sum[1][x-1];
    }
    for(int i=2;i<=n;i++)
    {
        head=tail=0;
        for(int j=m;j>=1;j--) left(i,j);
        head=tail=0;
        for(int j=1;j<=m;j++) right(i,j);
    }
}
Int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while (cin >> n >> m >> x >> t)
    {
        memset(sum, 0, sizeof(sum));
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
            {
                cin >> a[i][j];
                sum[i][j] = sum[i][j - 1] + a[i][j];
            }
        solve();
        int ans = dp[n][1];
        for (int i = 2; i <= m; i++)
            ans = max(ans, dp[n][i]);
        cout << ans << endl;
    }
    cin.get(), cin.get();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值