andre_joy

导航

hdu 4374

地址:http://acm.hdu.edu.cn/showproblem.php?pid=4374

题意:有n层,每层有m个模块,每个模块都有对应的权值,每层只能沿一个方向走,每层最多走t步,求最大权值的和。

mark:单调队列,dp[i][j]代表第i层,第j块最大的权值。

   首先每次求得dp[i][j]后,先向下走给dp[i+1][j]一个初始值,即dp[i+1][j] = dp[i][j]+w[i+1][j],(w[i][j]表示第i层第j块的权值。)

   然后单调队列,左边右边各弄一次,去最大值。

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int N = 110;
const int M = 10010;
int n,m,x,t;
int w[N][M],sum[N][M],dp[N][M];
int s1[M],s2[M];
int q[M],fr,la;

int max(int a, int b) {return a > b ? a : b;}

void left(int i)
{
    int j;
    for(j = 1; j <= m; j++)
        s1[j] = -10000000;
    fr = la = 0;
    q[la++] = 1;
    s1[1] = dp[i][1];
    for(j = 2; j <= m; j++)
    {
        if(j-q[fr] > t) fr += j-q[fr]-t;
        while(fr != la && dp[i][j] >= dp[i][q[la-1]]+sum[i][j]-sum[i][q[la-1]]) la--;
        q[la++] = j;
        s1[j] = dp[i][q[fr]]+sum[i][j]-sum[i][q[fr]];
    }
}

void right(int i)
{
    int j;
    for(j = 1; j <= m; j++)
        s2[j] = -10000000;
    fr = la = 0;
    q[la++] = m;
    s2[m] = dp[i][m];
    for(j = m; j > 0; j--)
    {
        if(q[fr]-j > t) fr += q[fr]-j-t;
        while(fr != la && dp[i][j] >= dp[i][q[la-1]]+sum[i][q[la-1]-1]-sum[i][j-1]) la--;
        q[la++] = j;
        s2[j] = dp[i][q[fr]]+sum[i][q[fr]-1]-sum[i][j-1];
    }
}

void solve()
{
    int i,j,k;
    int sum1;
    sum1 = 0;
    for(i = x; i > 0 && i >= x-t; i--)
    {
        sum1 += w[1][i];
        dp[1][i] = sum1;
        dp[2][i] = dp[1][i]+w[2][i];
    }
    sum1 = w[1][x];
    for(i = x+1; i <= m && i <= x+t; i++)
    {
        sum1 += w[1][i];
        dp[1][i] = sum1;
        dp[2][i] = dp[1][i]+w[2][i];
    }
    for(i = 2; i <= n; i++)
    {
        left(i);
        right(i);
        for(j = 1; j <= m; j++)
        {
            dp[i][j] = max(s1[j], s2[j]);
            dp[i+1][j] = dp[i][j]+w[i+1][j];
        }
    }
}

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    int i,j;
    while(~scanf("%d%d%d%d", &n, &m, &x, &t))
    {
        for(i = 0; i < n; i++)
            for(j = 0; j <= m; j++)
                dp[i][j] = -10000000;
        for(i = 0; i < N; i++)
            sum[i][0] = 0;
        for(i = 1; i <= n; i++)
            for(j = 1; j <= m; j++)
            {
                scanf("%d", &w[i][j]);
                sum[i][j] = w[i][j]+sum[i][j-1];
            }
        solve();
        int max1 = -10000000;
        for(i = 1; i <= m; i++)
            max1 = max(max1, dp[n][i]);
        printf("%d\n", max1);
    }
    return 0;
}

posted on 2012-08-17 16:30  andre_joy  阅读(227)  评论(0编辑  收藏  举报