费用提前计算相关的DP(BZOJ2037,POJ3042,ZOJ3469)

在刷ZeroClock大神的区间DP专辑,遇见了ZOJ3469,完全不无从下手,然后有人说是论问题,推荐看徐源盛《对一类动态规划问题的研究》这篇论文,果断得膜拜了下,感觉好神奇,可以把未来的费用提前计算好~~~顺便把相关的三道题A了,其实都是一样的。。。

BZOJ2037 [Sdoi2008]Sue的小球

题目大意

中文的。。。

题解

这是论文的例题

直接上原文的讲解吧。。。

费用提前计算相关的DP(BZOJ2037,POJ3042,ZOJ3469)

把dp数组初始化为0x7fffffffWA了,改成0x3f3f3f3f就AC了。。。

代码:

#include <iostream>

#include <algorithm>

#include <cstdio>

#include <cstring>

#include <utility>

using namespace  std;

#define MAXN 1005

#define INF 0x3f3f3f3f

int dp[2][MAXN][MAXN];

int sum[MAXN];

bool visit[MAXN][MAXN];

int n,x0;

typedef struct

{

    int x,y,v;

} NODE;

NODE a[MAXN];

bool cmp(const NODE a,const NODE b)

{

    return a.x<b.x;

}

void dfs(int l,int r)

{

    if(visit[l][r]) return;

    if(l==r)

    {

        if(a[r].x==x0)

            dp[0][l][r]=dp[1][l][r]=0;

        else dp[0][l][r]=dp[1][l][r]=-INF;

        return;

    }

    visit[l][r]=1;

    dfs(l+1,r);

    dfs(l,r-1);

    dp[0][l][r]=a[l].y+max(dp[0][l+1][r]-(a[l+1].x-a[l].x)*(sum[n]-sum[r]+sum[l]),

                                    dp[1][l+1][r]-(a[r].x-a[l].x)*(sum[n]-sum[r]+sum[l]));

    dp[1][l][r]=a[r].y+max(dp[1][l][r-1]-(a[r].x-a[r-1].x)*(sum[n]-sum[r-1]+sum[l-1]),

                                    dp[0][l][r-1]-(a[r].x-a[l].x)*(sum[n]-sum[r-1]+sum[l-1]));

    return;

}

int main()

{

    scanf("%d%d",&n,&x0);

    for(int i=1; i<=n; i++)

        scanf("%d",&a[i].x);

    for(int i=1; i<=n; i++)

        scanf("%d",&a[i].y);

    for(int i=1; i<=n; i++)

        scanf("%d",&a[i].v);

    a[++n].x=x0;

    sort(a+1,a+n+1,cmp);

    sum[0]=0;

    for(int i=1; i<=n; i++)

        sum[i]=sum[i-1]+a[i].v;

    dfs(1,n);

    printf("%.3lf\n",(double)(max(dp[0][1][n],dp[1][1][n]))/1000.0);

    return 0;

}

 

POJ3042 Grazing on the Run

题目大意

在X坐标轴上有n堆草,有一条牛的初始位置是在坐标L,牛(移动速度为1个单位/s)每次可以向左或者向右把一堆草吃掉,每堆草有一个腐烂度,它的值等于牛从开始到吃它位置的时间,牛想把所有草吃完之后,腐烂值的总和最小

题解

先对坐标进行排序,然后就进行DP,方程和BZOJ2037是一样的~~~

代码:

#include <iostream>

#include <algorithm>

#include <cstdio>

#include <cstring>

using namespace std;

#define INF 0x3f3f3f3f

#define MAXN 1005

int dp[2][MAXN][MAXN];

int x[MAXN];

int n,x0;

int main()

{

    scanf("%d%d",&n,&x0);

    for(int i=1;i<=n;i++)

        scanf("%d",&x[i]);

    x[++n]=x0;

    sort(x+1,x+n+1);

    for(int i=1;i<=n;i++)

        if(x[i]!=x0)dp[0][i][i]=dp[1][i][i]=INF;

        else

            dp[0][i][i]=dp[1][i][i]=0;

    for(int i=n;i>=1;i--)

        for(int j=i+1;j<=n;j++)

        {

            dp[0][i][j]=min(dp[0][i+1][j]+(x[i+1]-x[i])*(n-j+i),

                            dp[1][i+1][j]+(x[j]-x[i])*(n-j+i));

            dp[1][i][j]=min(dp[1][i][j-1]+(x[j]-x[j-1])*(n-j+i),

                            dp[0][i][j-1]+(x[j]-x[i])*(n-j+i));

        }

        printf("%d\n",min(dp[0][1][n],dp[1][1][n]));

        return 0;                                                      

}

 

ZOJ3469  Food Delivery

题目大意

和上题没啥区别。。。

有n个人叫餐,每个人都在x轴上,并且每个人都有个坑爹度(和等餐时间有关,据说顾客认为坑爹值到一定程度他的小宇宙就要爆发).现在送餐员从x轴上的某点出发,路上奔跑速度是v,要一次性把所有餐送完。叫餐的人得到餐的时间和顺序不同,坑爹度总和也就不同

题解

同上。。。

代码:

#include <algorithm>

#include <cstdio>

#include <cstring>

using namespace  std;

#define MAXN 1005

#define x first

#define y second

#define INF 0x3f3f3f3f

int dp[2][MAXN][MAXN];

int sum[MAXN];

bool visit[MAXN][MAXN];

pair<int,int>a[MAXN]; 

int n,v,x0;

void dfs(int l,int r)

{

    if(visit[l][r]) return;

    if(l==r)       

    {

        if(a[l].x==x0)dp[0][l][r]=dp[1][l][r]=0;

        else

            dp[0][l][r]=dp[1][l][r]=INF;

        return;

    }

    visit[l][r]=true;

    dfs(l+1,r);

    dfs(l,r-1);

    dp[0][l][r]=min(dp[0][l+1][r]+(a[l+1].x-a[l].x)*(sum[n]-sum[r]+sum[l]),

                          dp[1][l+1][r]+(a[r].x-a[l].x)*(sum[n]-sum[r]+sum[l]));

    dp[1][l][r]=min(dp[1][l][r-1]+(a[r].x-a[r-1].x)*(sum[n]-sum[r-1]+sum[l-1]),

                          dp[0][l][r-1]+(a[r].x-a[l].x)*(sum[n]-sum[r-1]+sum[l-1]));

}

int main()

{

    while(scanf("%d%d%d",&n,&v,&x0)!=EOF)

    {

        for(int i=1;i<=n;i++)

            scanf("%d%d",&a[i].x,&a[i].y);

        a[++n].x=x0;

        a[n].y=0;

        sort(a+1,a+n+1);

        sum[0]=0;

        for(int i=1;i<=n;i++)

            sum[i]=sum[i-1]+a[i].y;

        memset(visit,false,sizeof(visit));

        dfs(1,n);

        printf("%d\n",v*min(dp[0][1][n],dp[1][1][n]));

    }

    return 0;

}

你可能感兴趣的:(poj)