LA_3983Robotruck( 單調DP )

来源:互联网 发布:狙击步枪子弹编程图片 编辑:程序博客网 时间:2024/06/13 21:22
題意:一個機器人,收拾垃圾,收拾垃圾必須按照順序(性質很明顯),收拾完垃圾必須回到原點,兩點之間的距離是哈曼噸距離分析:很容易想出狀態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;}

原创粉丝点击