zoukankan      html  css  js  c++  java
  • uva3983

    这是一道思维层层递进的题。

    注意到N最大是100000,C最大是100,所以我们不能设时间复杂度为O(NC)的状态。

    只能设O(N)的状态了。

    设d(i)为从原点出发,将前i个垃圾全部扫完又回到原点的最小代价。(注意这里设的是从原点出发又回到原点,这是为了状态转移的方便而设)

    经典的想法还是把前i个垃圾进行分割。

    d(i) = min{d(j) + dist2origin[j + 1] + dist[j + 1,i] + dist2origin[i] | j <= i, w(j+1,i) <= C}

    搞完前j个的代价 + 从原点移动到j+1的代价 + 从j+1扫到i的代价 + 从i回到原点的代价。条件是在拿着j+1到i这一堆垃圾的时候总总量小于等于C。

    显然直接枚举是一个O(N2)的东西,我们想到dp加速。

    怎么加速,把与j有关的东西抽取出来,每次取当前可以选的j中的最小值。(因为与i有关的值可以O(1)求出)

    这就是利用了单调队列!

    把j相关的量分离出来有:

    d(i) = min(d(j) - total_dist[j+1]+dist2origin(j+1)) + total_dist[i] + dist2origin[i](j同样要满足上面的限制条件)

    如果令func(j) = d(j) - total_dist[j + 1] + dist2origin[j+1]

    则d(i) = min(func(j)) + total_dist[i] + dist2origin[i]

    这个用单调队列搞就好了。

    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 100005;
    
    int t, C, n;
    
    int dist2origin[maxn], total_dist[maxn], total_weight[maxn], f[maxn], q[maxn];
    
    struct node
    {
        int x, y, w;
    }a[maxn];
    
    int func(int i)
    {
        return f[i] - total_dist[i + 1] + dist2origin[i + 1]; 
    }
    
    void solve()
    {
        scanf("%d", &C);
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].w);
            dist2origin[i] = abs(a[i].x) + abs(a[i].y);
            total_dist[i] = total_dist[i - 1] + abs(a[i].x - a[i - 1].x) + abs(a[i].y - a[i - 1].y);
            total_weight[i] = total_weight[i - 1] + a[i].w;
        }
        int front = 1, rear = 1;
        for (int i = 1; i <= n; i++)
        {
            while (front <= rear && total_weight[i] - total_weight[q[front]] > C)//把已经不合适的队头元素清掉。
                front++;
            f[i] = func(q[front]) + total_dist[i] + dist2origin[i];//这样取出来的队头就是func值最小的元素。
            while (front <= rear && func(i) <= func(q[rear]))//保证队列是单调递增的。
                rear--;
            q[++rear] = i;//不要忘了
        }
        printf("%d
    ", f[n]);
        if (t > 0) printf("
    ");
    }
    
    int main()
    {
        scanf("%d", &t);
        while (t--) solve();
        return 0;
    }

    时间复杂度O(N)

  • 相关阅读:
    AJAX局部刷新
    jquery 调用数据
    java 节点流(字符流,字节流)和包装流(缓冲流,转换流)
    java File类的使用以及一些函数
    java 自定义泛型
    java 注解
    jdbc baseDAO 以及 每个类的继承
    jdbc 事物 commit 和rollback方法
    jdbc 可处理数据库事物的通用增删查改函数
    jdbc 数据库批处理insert操作
  • 原文地址:https://www.cnblogs.com/yohanlong/p/7765616.html
Copyright © 2011-2022 走看看