LA_3983 Robotruck( 單調DP )

題意:
一個機器人,收拾垃圾,收拾垃圾必須按照順序(性質很明顯),收拾完垃圾必須回到原點,兩點之間的距離是哈曼噸距離
分析:
很容易想出狀態O(N*M)的DP算法可惜狀態個數太多了,不得不這樣想:
f[i]表示機器人收拾完第i個垃圾並且回到了原點所需要的最小距離
這裏令ori[j] 表示第j個垃圾到原點的距離
dis[i], 垃圾1,2,3,... i的距離
不難推出狀態轉移: f[i] = min(f[j]+ori[j+1]+dis[i]-dis[j+1]+ori[i]) (w[j+1]...[i] <= cap)
這樣的時間複雜度還是不夠理想,於是把上述的等式變換一下:
f[i] = min(f[j]+ori[j+1]-dis[j+1])+ori[i]+dis[i]
令cal(j) = f[j]+ori[j+1]-dis[j+1]
則f[i] = min(cal[j])+ori[i]+dis[i]
由於cal是單調遞增的,可以根據cap的數值控制一個隊列的數據結構,使得隊列單調遞增
Code:
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;


#define DIR     4
#define DIM     2
#define STATUS  2
#define MAXM    1000 + 10
#define MAXN    100000 + 10
#define oo      (~0u)>>1
#define INF     0x3F3F3F3F
#define REPI(i, s, e)        for(int i = s; i <= e; i ++)
#define REPD(i, e, s)         for(int i = e; i >= s; i --)


static const double EPS = 1e-5;


int f[MAXN], w[MAXN], px[MAXN], py[MAXN], dis[MAXN], ori[MAXN];


inline int cal(int j)
{
        return f[j]+ori[j+1]-dis[j+1];
}


int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
        freopen("test.in", "r", stdin);
#endif
        int cas, cap, n, ww;
        scanf("%d", &cas);
        REPI(k, 1, cas) {
                scanf("%d %d", &cap, &n);
                ori[0] = w[0] = px[0] = py[0] = dis[0] = 0;
                REPI(i, 1, n) {
                        scanf("%d %d %d", &px[i], &py[i], &ww);
                        w[i] = w[i-1]+ww;
                        ori[i] = abs(px[i])+abs(py[i]);
                        dis[i] = dis[i-1]+abs(px[i]-px[i-1])+abs(py[i]-py[i-1]);
                }
                deque<int> q;
                q.push_back(0);
                //f[j] = min(f[j]+ori[j+1]-dis[j+1])+dis[i]+ori[i];
                REPI(i, 1, n) {
                        while( !q.empty() && w[i]-w[q.front()] > cap ) {
                                q.pop_front();
                        }
                        f[i] = cal(q.front())+dis[i]+ori[i];
                        while( !q.empty() && cal(q.back()) > cal(i) ) {
                                q.pop_back();
                        }
                        q.push_back(i);
                }
                if( 1 != k ) {
                        printf("\n");
                }
                printf("%d\n", f[n]);
        }
        return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章