题意:某城由n+1个横向路和m+1个竖向路组成,你的任务是从最南边的路走到最北边的路,使得走过的路上高兴值最大,同一条路不能经过两次,也不能从北向南走,另外,每条横向路有一个长度,在每一行的横向路行走的长度不能超过k
简单起见我们可以看成从北边走到南边
首先预处理数组sum[i][j]表示第i行从第1个点到第j个点的高兴值总和
用f[i][j]表示从i-1行往下走一行位于(i且,j)点时得到的最大的高兴值,我们先不考虑长度的限制,那么容易得到以下方程:
f[i][j]=max{f[i-1][k]+sum[i-1][max(j,k)]-sum[i-1][min(j,k)]}
由于sum[i-1][j]是一个相对常量,所以求f[i-1][k]+sum[i-1][k]的最大值(或求f[i-1][k]-sum[i-1][k]的最大值)要用到单调队列
那么有长度限制该怎么办呢?我们可以再预处理两个数组l[i],r[i]
l[i][j]表示在第i排从第j号点开始向左走能到达的最远的点(即这两个点之间的路的长度和<=k)
那么r[i][j]同理
使用g[j]=f[i-1][k]±sum[i-1][k],然后单调队列里记录编号,如果编号小于l[i][j]或者大于r[i][j]就将队首元素弹出
注意最后答案是max{f[n+2][i]}而不是max{f[n+1][i]}想一想为什么
#include<cstdio>
#include<iostream>
#include<deque>
using namespace std;
const int maxn=105,maxm=10005,inf=1e9;
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
int n,m,k,sum[maxn][maxm],t[maxn][maxm],g[maxm];
int f[maxn][maxm],l[maxn][maxm],r[maxn][maxm];
deque<int>q;
int main(){
while(scanf("%d%d%d",&n,&m,&k)&&(n||m||k)){
int i,j,x;
for(i=1;i<=n+1;i++)
for(j=1;j<=m;j++){
_read(x);
sum[i][j+1]=sum[i][j]+x;
}
for(i=1;i<=n+1;i++)
for(j=1;j<=m;j++)_read(t[i][j]);
for(i=1;i<=n+1;i++){
int cur=0,id=1;
l[i][1]=1,r[i][m+1]=m+1;
for(j=2;j<=m+1;j++){
cur+=t[i][j-1];
while(cur>k)cur-=t[i][id++];
l[i][j]=id;
}
cur=0,id=m;
for(j=m;j;j--){
cur+=t[i][j];
while(cur>k)cur-=t[i][id--];
r[i][j]=id+1;
}
}
for(i=1;i<=m+1;i++)f[n+1][i]=0;
for(i=2;i<=n+2;i++){
while(!q.empty())q.pop_back();
for(j=1;j<=m+1;j++){
g[j]=f[i-1][j]-sum[i-1][j];
while(!q.empty()&&q.front()<l[i-1][j])q.pop_front();
while(!q.empty()&&g[j]>=g[q.back()])q.pop_back();
q.push_back(j);
f[i][j]=max(f[i-1][j],sum[i-1][j]+g[q.front()]);
}
while(!q.empty())q.pop_back();
for(j=m+1;j;j--){
g[j]=f[i-1][j]+sum[i-1][j];
while(!q.empty()&&q.front()>r[i-1][j])q.pop_front();
while(!q.empty()&&g[j]>=g[q.back()])q.pop_back();
q.push_back(j);
f[i][j]=max(f[i][j],g[q.front()]-sum[i-1][j]);
}
}
int ans=0;
for(i=1;i<=m+1;i++)ans=max(ans,f[n+2][i]);
printf("%d\n",ans);
}
}

本文介绍了一种寻找从网格底部到顶部的路径算法,旨在最大化累积的高兴值,同时考虑到路径长度的约束条件。该算法利用了动态规划原理,并通过预处理数组和单调队列优化了计算效率。
3131

被折叠的 条评论
为什么被折叠?



