HDU 4362 Dragon Ball【dp优化】

题意: 在连续的 n 秒中,每秒会出现 m 个龙珠,出现之后会立即消失,知道了第一秒所在的位置,每从一个位置移动到另一个位置的时候,消耗的价值为

          abs(i-j), 知道了次出现的龙珠的价值,问 n 秒之后得到的最大价值是多少。

分析: 当 pos[i][j] >= pos[i-1][k] 时:dp[i][j]= min( dp[i-1][k] -  pos[i-1][k] ) + pos[i][j] + w[i][j];
          当 pos[i][j] <= pos[i-1][k] 时:dp[i][j]= min( dp[i-1][k] + pos[i-1][k] ) - pos[i][j] + w[i][j];
          遇到 dp[i]= max/min( b[i-1] )+ a 形式时,可考虑单调队列,这里可以事先对每秒中出现的位置排好序,这样就可以降维。

#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
#include <math.h>
using namespace std;
#define INF 0x1f1f1f1f
#define clr(x)memset(x,0,sizeof(x))
int min(int a,int b)
{
    return a<b?a:b;
}
int ab(int x)
{
    return x>0?x:-x;
}
struct node
{
    int pos, w;
}b[60][1005];
int dp[60][1005];
int q[1005];
bool cmp(node a,node b)
{
    return a.pos<b.pos;
}
int main()
{
    int i, j, k;
    int t, x, n, m;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n, &m, &x);
        for(i = 0; i < n; i++)
            for(j = 0; j < m; j++)
                scanf("%d",&b[i][j].pos);
        for(i = 0; i < n; i++){
            for(j = 0; j < m; j++)
                scanf("%d",&b[i][j].w);
            sort(b[i],b[i]+m,cmp);
        }
        for(i = 0; i < m; i++)
            dp[0][i] = ab(x-b[0][i].pos)+b[0][i].w;
        int dmin;
        for(i = 1; i < n; i++){
            k = 0;
            dmin = INF;
            for(j = 0; j < m; j++){
                while(k < m && b[i][j].pos >= b[i-1][k].pos){
                    dmin = min(dp[i-1][k]-b[i-1][k].pos,dmin);
                    k++;
                }
                dp[i][j] = dmin + b[i][j].pos + b[i][j].w;
            }
            k = m-1;
            dmin = INF;
            for(j = m-1; j >= 0; j--){
                while(k >= 0 && b[i][j].pos <= b[i-1][k].pos){
                    dmin = min(dp[i-1][k]+b[i-1][k].pos,dmin);
                    k--;
                }
                dp[i][j] = min(dp[i][j],dmin-b[i][j].pos+b[i][j].w);
            }
        }
        dmin = dp[n-1][0];
        for(i = 1; i < m; i++)
            dmin = min(dmin,dp[n-1][i]);
        printf("%d\n",dmin);
    }
    return 0;
}

 

posted @ 2012-10-12 20:05  'wind  阅读(442)  评论(0编辑  收藏  举报