LA3983 Robotruck


題目描述
這裏寫圖片描述


藍書上的例題,我重新推導一遍。
d(i) 表示撿完前i 個垃圾需要走的最短距離。
d(i)=min{d(j)+dist0(j+1)+dist(j+1,i)+dist0(i) | w(j+1,i)<=c}
其中:
dist0(i) 表示i 到原點的距離;
dist(i,j) 表示從第i 個垃圾走到第i+1,i+2...j 個垃圾的距離;
w(i,j) 表示i ~j 個垃圾的總重量。
如果預處理出tot_d(i) (原點依次經過1,2…i個垃圾的總距離)那麼:
d(i)=min{d(j)+dist0(j+1)+tot_d(i)tot_d(j+1)+dist0(i)}
func(i)=d(i)tot_d(i+1)+dist0(i+1)
那麼d(i)=min{func(j) | w(j+1,i)<=c}+tot_d(i)+dist0(i)
單調隊列維護func(j) 可在O(1) 時間完成轉移。
代碼

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=100010;
int d[maxn],tot_d[maxn],tot_w[maxn],dist0[maxn],q[maxn],x[maxn],y[maxn],w;
int func(int i){
    return d[i]-tot_d[i+1]+dist0[i+1];
}
int main(){
    int t;
    cin>>t;
    x[0]=y[0]=tot_w[0]=tot_d[0]=q[0]=0;;
    while(t--){
        int c,n;
        scanf("%d%d",&c,&n);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&x[i],&y[i],&w);
            tot_w[i]=w+tot_w[i-1];
            tot_d[i]=abs(x[i]-x[i-1])+abs(y[i]-y[i-1])+tot_d[i-1];
            dist0[i]=abs(x[i])+abs(y[i]);
        }
        int head=0,tail=1;
        for(int i=1;i<=n;i++){
            while(head<tail&&tot_w[i]-tot_w[q[head]]>c) head++;
            d[i]=func(q[head])+tot_d[i]+dist0[i];
            while(head<tail&&func(q[tail])>=func(i)) tail--;
            q[++tail]=i;
        }
        printf("%d\n",d[n]);
        if(t>0) puts("");
    }
    return 0;
}
發佈了59 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章