您的位置:首页 > 其它

hdu 4374 One hundred layer【单调队列DP】

2012-12-20 21:16 363 查看

One hundred layer

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1131 Accepted Submission(s): 422



[align=left]Problem Description[/align]
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.

[align=left]Input[/align]
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)

[align=left]Output[/align]
Output the highest score you can get.

[align=left]Sample Input[/align]

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


[align=left]Sample Output[/align]

29


题目分析:一个n层的楼,每层楼有m个格子,每个格子有一定的价值。在每一层楼只能向一个方向走最多走t步,开始在顶层的x位置,问到底层的路线上能得到的价值最大。

第一次在青理见到它时,我一眼看出就是Dp,可是不知道怎么优化,只能看着它Tle。。。。。。

可以从下往上走,每个状态dp[i][j]为从i层j格子到底层所能得到的最大价值。用sum[i][j]表示第i层前j-1格子的和。

从左边到j位置的状态转移方程 dp[i][j]=max(dp[i+1][k]+sum[i][j+1]-sum[i][k]);(k+t<j)。

上式即为:dp[i][j]=max(dp[i+1][k]-sum[i][k])+sum[i][j+1];

由于max里面包含的项都已知切与j无关。故可以用单调队列,

其右边的状态转移方程为dp[i][j]=max(dp[i+1][k]+sum[i][k]+1)-sum[i][j];

代码:

#include<iostream>
#include<cstdio>
#define N 105
#define M 10005
using namespace std;
int dp
[M];
int sum
[M];
int n,m,x,t;
int q[M];
void solve()
{
int an1[M],an2[M];
int front,rear;
for(int i=n-1; i>=0; i--)
{
front=0;
rear=0;
q[rear++]=0;
an1[0]=0;
for(int j=1; j<m; j++)
{
while(front<rear&&dp[i+1][q[rear-1]]-sum[i][q[rear-1]]<=dp[i+1][j]-sum[i][j])//这里很关键。。。
rear--;
q[rear++]=j;
if(q[front]+t<j)
front++;
an1[j]=q[front];
}
front=0;
rear=0;
q[rear++]=m-1;
an2[m-1]=m-1;
for(int j=m-2; j>=0; j--)
{
while(front<rear&&dp[i+1][q[rear-1]]+sum[i][q[rear-1]+1]<=dp[i+1][j]+sum[i][j+1])
rear--;
q[rear++]=j;
if(q[front]-t>j)
front++;
an2[j]=q[front];
}
int t1,t2;
for(int j=0; j<m; j++)
{
t1=dp[i+1][an1[j]]+sum[i][j+1]-sum[i][an1[j]];
t2=dp[i+1][an2[j]]+sum[i][an2[j]+1]-sum[i][j];
dp[i][j]=t1>t2?t1:t2;
}
}
}
int main()
{
int sum1,a;
freopen("in.txt","r",stdin);
while(scanf("%d%d%d%d",&n,&m,&x,&t)!=EOF)
{
for(int i=0; i<n; i++)
{
sum1=0;
sum[i][0]=0;
for(int j=0; j<m; j++)
{
scanf("%d",&a);
sum1+=a;
sum[i][j+1]=sum1;
}
}
for(int j=0; j<m; j++)
{
dp
[j]=0;
}
solve();
printf("%d\n",dp[0][x-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: