HDOJ4362-決策單調的DP

易得此題DP方程: dp[i][j]=min{dp[i-1][k]+abs(x[i-1][k]-x[i][j])}+cost[i][j]; //1<=i<=n,1<=j,k<=m;

當x[i-1][k]<=x[i][j]時,dp[i][j]=min{dp[i-1][k]-x[i-1[k]}+x[i][j]+cost[i][j]; (1)

當x[i-1][k]>x[i][j]時,dp[i][j]=min{dp[i-1][k]+x[i-1][k]}-x[i][j]+cost[i][j];  (2)

(1)和(2)式中的min{}部分均與j無關,單調性明顯。

故可對點[i][j]按座標排序,對於每層,從左往右(1),從右往左(2)兩次,在座標關係滿足x[i-1][k]<=x[i][j](x[i-1][k]>x[i][j])中找到dp[i-1][k]-x[i-1][k](dp[i-1][k]+x[i-1][k])最小的點再做轉移即可。

AC代碼如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int NN=1010;
const int INF=0x3fffffff;

int dp[2][NN];
struct node{
    int x,w;
    bool operator <(const node a)const{
        return x<a.x;
    }
}a[NN][NN];

int main()
{
    int T,c,n,m,k,v,x0;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d",&n,&m,&x0);
        for (int i=1; i<=n; i++)
          for (int j=1; j<=m; j++) scanf("%d",&a[i][j].x);
        for (int i=1; i<=n; i++)
        {
            for (int j=1; j<=m; j++) scanf("%d",&a[i][j].w);
            sort(a[i]+1,a[i]+m+1);
            a[i][m+1].x=INF;
            a[i][0].x=-1;
        }

        //dp
        for (int j=1; j<=m; j++) dp[1][j]=abs(a[1][j].x-x0)+a[1][j].w;
        c=1;
        for (int i=2; i<=n; i++)
        {
            c=i%2;
            v=0; k=1;
            for (int j=1; j<=m; j++)
            {
                dp[c][j]=INF;
                while (a[i-1][k].x<=a[i][j].x)
                {
                    if (!v || dp[c^1][v]-a[i-1][v].x>dp[c^1][k]-a[i-1][k].x) v=k;
                    k++;
                }
                if (v)
                    dp[c][j]=min(dp[c][j],dp[c^1][v]-a[i-1][v].x+a[i][j].x+a[i][j].w);
            }
            v=0; k=m;
            for (int j=m; j; j--)
            {
                while (a[i-1][k].x>=a[i][j].x)
                {
                    if (!v || dp[c^1][v]+a[i-1][v].x>dp[c^1][k]+a[i-1][k].x) v=k;
                    k--;
                }
                if (v)
                    dp[c][j]=min(dp[c][j],dp[c^1][v]+a[i-1][v].x-a[i][j].x+a[i][j].w);
            }
        }

        int ans=INF;
        for (int j=1; j<=m; j++) ans=min(ans,dp[c][j]);
        printf("%d\n",ans);
    }
    return 0;
}


發佈了100 篇原創文章 · 獲贊 2 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章