首页 > 代码库 > POJ 3042 Grazing on the Run (区间DP)

POJ 3042 Grazing on the Run (区间DP)


区间dp,~~~~
dp[i][j][0]表示i到j之间已经走过,并且现在在i点的staleness(可以理解为枯萎指数)最小值,
dp[i][j][1]表示i到j之间已经走过,并且现在在j点的staleness最小值。
于是对于在i点,可能从i+1->i,也可能从j->i,即:
很重要的一点,在我们转移到i时,除了即将到达的i点,还有未到达的(n-(j-i+1))个点,即总共(n-(j-i))个点,它们的枯萎指数均在增加,so~
dp[i][j][0]=min(dp[i+1][j][0]+(n-(j-i))*(pos[i+1]-pos[i]),dp[i+1][j][1]+(n-(j-i))*(pos[j]-pos[i]));
同理对于当前在j点,也可以得到向相应的方程:
dp[i][j][1]=min(dp[i][j-1][1]+(n-(j-i))*(pos[j]-pos[j-1),dp[i][j-1][0]+(n-(j-i))*(pos[j]-pos[i])).
最后需要注意的就是初始话的问题了,找到L在原序列中的位置就好。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

题目链接:http://poj.org/problem?id=3042


#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000+10
using namespace std;

int p[N];
int f[N][N][2];
int main()
{
    int n,s;
    while(~scanf("%d%d",&n,&s))
    {
        int ok=1;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&p[i]);
            if(p[i]==s) ok=0; //可能存在某点与起点重合的情况。
        }
        if(ok) p[n++]=s;
        sort(p,p+n);
        int pos=lower_bound(p,p+n,s)-p; //二分查找L的位置。
        memset(f,0x3f,sizeof(f));   
        f[pos][pos][0]=f[pos][pos][1]=0; //起点~
        for(int i=pos;i>=0;i--)
        {
            for(int j=pos;j<n;j++)
            {
                f[i][j][0]=min(f[i][j][0],f[i+1][j][0]+(n-(j-i))*(p[i+1]-p[i]));
                f[i][j][0]=min(f[i][j][0],f[i+1][j][1]+(n-(j-i))*(p[j]-p[i]));
                f[i][j][1]=min(f[i][j][1],f[i][j-1][1]+(n-(j-i))*(p[j]-p[j-1]));
                f[i][j][1]=min(f[i][j][1],f[i][j-1][0]+(n-(j-i))*(p[j]-p[i]));
            }
        }
        printf("%d\n",min(f[0][n-1][0],f[0][n-1][1]));
    }
    return 0;
}