您的位置:首页 > 其它

hdu 4374 dp+单调队列优化

2012-08-17 15:30 429 查看
/*

解法: dp+单调队列!

有一个的楼房,从第一层某个位置出发上楼,每次能爬上一层楼也可以在同一层左右移动,

但是在每一层的移动距离不能超过某个值。。现在每个位置都有一个数值,

求从第一层出发到最后一层经过的路径上最多能取到的最大价值。

dp[i][j] 表示 第i行,第j个数字的最大价值!

sum[i][j] 表示 第i行 第j个数字的成绩和!

那么 在 j 左边的数据状态转移方程为:

dp[i][j]=min(dp[i-1][k]+sum[i][j]-sum[i][k-1]);

在 j 右边的数据状态转移方程为:

dp[i][j]=min(dp[i-1][k]-sum[i][j-1]+sum[i][k]);

*/

#include<iostream>

#include<cstdio>

#include<algorithm>

#include<memory.h>

#include<math.h>

using namespace std;

const int maxn=102;

const int maxm=10002;

int n,m,x,t,l,r;

int dp[maxn][maxm],sum[maxn][maxm],sc[maxn][maxm],q[maxm];

int cost1(int i,int k,int j)

{

return dp[i-1][k]+sum[i][j]-sum[i][k-1];

}

int cost2(int i,int k,int j)

{

return dp[i-1][k]-sum[i][j-1]+sum[i][k];

}

int main()

{

int i,j,k,head,tail;

while(scanf("%d%d%d%d",&n,&m,&x,&t)!=EOF)

{

for(i=1; i<=n; i++)

{

for(j=1; j<=m; j++)

{

scanf("%d",&sc[i][j]);

sum[i][j]=sum[i][j-1]+sc[i][j];

dp[i][j]=0;

}

}

//for(i=1;i<=m;i++)sum[n+1][i]=sum
[i];

for(i=x+1; i<=x+t; i++)

dp[1][i]=sum[1][i]-sum[1][x-1];

for(i=x-t; i<=x; i++)

dp[1][i]=sum[1][x]-sum[1][i-1];

for(i=2; i<=n; i++)

{

head=tail=0;

l=1;

r=m;

for(j=1; j<=m; j++)

{

while(l<=j)

{

if(!dp[i-1][l]||l+t<j)

{

l++;

continue;

}

int tmp=cost1(i,l,j);

while(tail>head&&cost1(i,q[tail-1],j)<tmp)tail--;

q[tail++]=l++;

if(q[head]<j-t) head++;

}

while(q[head]<j-t) head++;

if(tail>head) dp[i][j]=cost1(i,q[head],j);

}

head=tail=0;

for(j=m; j>=1; j--)

{

while(r>=j)

{

if(!dp[i-1][r]||r-t>j)

{

r--;

continue;

}

int tmp=cost2(i,r,j);

while(tail>head&&cost2(i,q[tail-1],j)<tmp)tail--;

q[tail++]=r--;

if(q[head]>j+t) head++;

}

while(q[head]-t>j) head++;

if(tail>head) dp[i][j]=max(dp[i][j],cost2(i,q[head],j));

}

}

int ans=0;

for(i=1; i<=m; i++)

{

if(ans<dp
[i]) ans=dp
[i];

}

cout<<ans<<endl;

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: