ZOJ 3469 区间DP

题意

一个人从X点出发给N个点送食物,速度为1/v,如果第xi个点的客人没有收到食物,那么他的不满意度将会增加bi每分钟。问不满意度最少为多少?

题解

很有趣的一道区间DP题,将出发点也放入点集中,排序,进行区间DP。
dp[i][j][0]代表该人在I处,I到J的所有客人都已配送完成时最少的不满意度。
dp[i][j][1]代表该人在J处,I到J的所有客人都已配送完成时最少的不满意度。
由此可以得到状态转移方程

dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(nodes[i+1].x-nodes[i].x)*(lt[i]+rt[j+1]));
                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(nodes[j].x-nodes[i].x)*(lt[i]+rt[j+1]));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(nodes[j].x-nodes[i].x)*(lt[i-1]+rt[j]));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(nodes[j].x-nodes[j-1].x)*(lt[i-1]+rt[j]));

代码

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 1010
#define EPS 1e-10
#define MOD 100000000

using namespace std;

struct Node {
    int x,b;

    bool operator <(const Node b) const {
        return x<b.x;
    }
};

Node nodes[MAXN];
int dp[MAXN][MAXN][2];
int lt[MAXN],rt[MAXN];

int main() {
    int n,v,x;
    W(~scanf("%d%d%d",&n,&v,&x)) {
        UP(i,0,n) {
            scanf("%d%d",&nodes[i].x,&nodes[i].b);
        }
        nodes[n].x=x,nodes[n].b=0;
        n++;
        sort(nodes,nodes+n);
        MEM(dp,INF);
        int pos=0;
        UP(i,0,n) {
            if(nodes[i].x==x)
                pos=i;
        }
        MEM(lt,0);
        MEM(rt,0);
        lt[0]=nodes[0].b;
        UP(i,1,n) {
            lt[i]=lt[i-1]+nodes[i].b;
        }
        rt[n-1]=nodes[n-1].b;
        DOWN(i,n-1,0) {
            rt[i]=rt[i+1]+nodes[i].b;
        }
        dp[pos][pos][0]=dp[pos][pos][1]=0;
        UP(len,1,n) {
            UP(i,0,n) {
                int j=i+len;
                if(j>=n) {
                    continue;
                }
//                cout<<i<<" "<<j<<endl;
                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(nodes[i+1].x-nodes[i].x)*(lt[i]+rt[j+1]));
                dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(nodes[j].x-nodes[i].x)*(lt[i]+rt[j+1]));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(nodes[j].x-nodes[i].x)*(lt[i-1]+rt[j]));
                dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(nodes[j].x-nodes[j-1].x)*(lt[i-1]+rt[j]));
            }
        }
//        cout<<dp[0][n][0]*v<<" "<<dp[0][n][1]*v<<endl;
        printf("%d\n",min(dp[0][n-1][0]*v,dp[0][n-1][1]*v));
    }
}

/*
5 1 5
1 1
2 2
3 3
4 4
5 5
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值