题目
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1984
题意
按顺序给出平面n个点,每个点上都有重物,一次只能按顺序拿重量不超过c的重物,从原点出发并且返回原点,问至少多少次能把全部重物拿回原点
思路
明显,令dp[i]为从1拿到i所需的最小出发次数,令dist0[i]为从原点到i的距离,令dist[i]为从i到i-1的距离(点0不妨设置为原点),令distSum[i] = sum(dist[0]...dist[i]),则dp[j] = dp[j] + dist0[j] + distSum[j] + dp[i] + dist0[i + 1] - distSum[i+1],此处j > i且i+1...j的重物重量和不超过c。设mycost[i] = dp[i] + dist0[i + 1] - distSum[i+1],明显,可以使用尺取+优先队列来维护重量和不超过c和 dp[i] + dist0[i + 1] - distSum[i+1]最小这两个条件。
但刘书提出了进一步优化:由于当新加入的点i的mycost比尺取区间中维护的旧点小的时候,这些旧点是没有用的,可以不考虑它们。当这样做了之后,剩下的点总能成为一个递增序列,这样就非常容易维护。
感想
一开始DP公式推错了,弄成了还从该点出发
代码
#include <algorithm> #include <cassert> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <queue> #include <set> #include <string> #include <tuple> #define LOCAL_DEBUG using namespace std; typedef pair<int, int> MyPair; const int MAXN = 1e5 + 5; int n, c; int x[MAXN]; int y[MAXN]; int w[MAXN]; int wSum[MAXN]; int distSum[MAXN]; int dist0[MAXN]; int dp[MAXN]; int mydeque[MAXN]; int mycost[MAXN]; #define MYCOST(x) (dist0[(x) + 1] - distSum[(x) + 1] + dp[(x)]) int main() { #ifdef LOCAL_DEBUG freopen("C:\Users\Iris\source\repos\ACM\ACM\input.txt", "r", stdin); //freopen("C:\Users\Iris\source\repos\ACM\ACM\output.txt", "w", stdout); #endif // LOCAL_DEBUG int T; scanf("%d", &T); for (int ti = 1; ti <= T && scanf("%d%d", &c, &n) == 2; ti++) { for (int i = 1; i <= n; i++) { scanf("%d%d%d", x + i, y + i, w + i); dist0[i] = abs(x[i]) + abs(y[i]); } for (int i = 1; i <= n; i++) { wSum[i] = w[i] + wSum[i - 1]; distSum[i] = abs(x[i] - x[i - 1]) + abs(y[i] - y[i - 1]); distSum[i] += distSum[i - 1]; } int dequeTop = 0; int dequeEnd = 0; mydeque[dequeEnd++] = 0; for (int i = 1; i <= n; i++) { while (dequeTop < dequeEnd && wSum[i] - wSum[mydeque[dequeTop]] > c) { dequeTop++; } assert(dequeTop < dequeEnd); int f = mydeque[dequeTop]; dp[i] = dist0[i] + dist0[f + 1] + distSum[i] - distSum[f + 1] + dp[f]; while (dequeTop < dequeEnd && MYCOST(mydeque[dequeEnd - 1]) >= MYCOST(i)) { dequeEnd--; } mydeque[dequeEnd++] = i; } if (ti != 1)puts(""); printf("%d ", dp[n]); } return 0; }