一.题目链接:
ZOJ-3469
二.题目大意:
在数轴上有 n 个顾客,在 x 点有一个外卖员,外卖员走一米需要 v 秒,每秒顾客 i 的怒气值增加 b[i]
求送完 n 个顾客的外卖后,n 个顾客怒气值和的最小值.
三.分析:
这题的 DP 状态表示很有意思,dp[i][j][0/1] 表示送完区间 [i, j] 后,且外卖员在 i/j 点,n 个顾客怒气值和的最小值.
也就是说,dp 状态表示并非是当前子区间所代表区间状态的属性,而是作为总集合达到现状态的总集合花费.(鬼知道我在胡扯什么
四.代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = (int)1e3;
const int inf = 0x3f3f3f3f3f3f3f3f;
struct node
{
int x, b;
}s[M + 5];
ll dp[M + 5][M + 5][2];
ll sum[M + 5];
bool cmp(node a, node b)
{
return a.x < b.x;
}
int main()
{
int n, v, x;
while(~scanf("%d %d %d", &n, &v, &x))
{
for(int i = 1; i <= n; ++i)
scanf("%d %d", &s[i].x, &s[i].b);
s[++n].x = x, s[n].b = 0;
sort(s + 1, s + n + 1, cmp);
for(int i = 1; i <= n; ++i)
sum[i] = sum[i - 1] + s[i].b;
int start = 0;
while(s[++start].x != x);
memset(dp, inf, sizeof(dp));
dp[start][start][0] = dp[start][start][1] = 0;
for(int i = start; i >= 1; --i)
{
for(int j = start; j <= n; ++j)
{
dp[i][j][0] = min(dp[i][j][0], dp[i + 1][j][0] + (s[i + 1].x - s[i].x) * (sum[n] - (sum[j] - sum[i])));
dp[i][j][0] = min(dp[i][j][0], dp[i + 1][j][1] + (s[j].x - s[i].x) * (sum[n] - (sum[j] - sum[i])));
dp[i][j][1] = min(dp[i][j][1], dp[i][j - 1][0] + (s[j].x - s[i].x) * (sum[n] - (sum[j - 1] - sum[i - 1])));
dp[i][j][1] = min(dp[i][j][1], dp[i][j - 1][1] + (s[j].x - s[j - 1].x) * (sum[n] - (sum[j - 1] - sum[i - 1])));
}
}
printf("%lld\n", min(dp[1][n][0], dp[1][n][1]) * v);
}
return 0;
}