UVA LA 3983

题目

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;
}
View Code
原文地址:https://www.cnblogs.com/xuesu/p/10457160.html