區間 [動態規劃]

區間


\color{red}{正解部分}

首先 一個點最多被兩個區間覆蓋,

若按常規套路設 F[i]F[i] 表示處理到前 ii 個區間覆蓋 [1,ri][1, r_i] 的最小代價,
轉移: F[i]=min(F[i],max(F[k], wi+[rkli1]×wk))F[i] = \min(F[i], \max(F[k],\ w_i +[r_k\not =l_i-1]\times w_k))

如下圖, F[i]F[i] 如果從 F[k]F[k] 轉移過來, 會 “忽略” jj 的存在, 導致答案變爲 88,

在轉移時並不知道轉移的來源會與哪些區間重合, 導致並不知道這個區間會與哪些區間重合,
換就話說, 轉移的來源並不純淨,
我們需要轉移的時候使得兩個區間相交的區域沒有別的區間存在, 於是可以想到多設一維去保證上述條件 .

F[i,j]F[i, j] 表示處理到第 ii 個區間, (j,ri](j, r_i] 被覆蓋一次的 最大值,
假設從第 kk 個區間轉移而來, 前提是 rkli1r_k \geq l_i-1, 分情況討論,

  • rk=li1r_k = l_i-1, F[i,rk]=min(F[i,rk], max(F[k,1 ... li1],wi))F[i, r_k] = \min\left(F[i, r_k],\ \max(F[k, 1\ ...\ l_i-1], w_i)\right)
  • rklir_k \geq l_i, F[i,rk]=min(F[i,rk], max(F[k,1 ... li1],wi+wk))F[i, r_k] = \min\left(F[i, r_k], \ \max(F[k, 1\ ... \ l_i-1], w_i+w_k)\right)

\color{red}{實現部分}

#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 3005;
const int inf = 0x3f3f3f3f;

int N;
int M;
int F[maxn][maxn];

struct Intval{ int l, r, w; } A[maxn];

bool cmp(Intval a, Intval b){ return a.r < b.r; }

void Work(){
        N = read(), M = read();
        for(reg int i = 1; i <= N; i ++) A[i].l = read(), A[i].r = read(), A[i].w = read();
        std::sort(A+1, A+N+1, cmp);
        for(reg int i = 1; i <= N; i ++){
                for(reg int j = 0; j <= M; j ++) F[i][j] = inf;
                for(reg int j = i; j >= 0; j --){
                        if(A[j].r < A[i].l-1) break ;
                        F[i][A[j].r] = std::min(F[i][A[j].r], std::max(F[j][A[i].l-1], (A[j].r==A[i].l-1?0:A[j].w) + A[i].w));
                }
                for(reg int j = 1; j <= M; j ++) F[i][j] = std::min(F[i][j], F[i][j-1]);
        }
        int Ans = inf;
        for(reg int i = N; i >= 1; i --){ if(A[i].r < M) break ; Ans = std::min(Ans, F[i][A[i].r]); }
        printf("%d\n", Ans==inf?-1:Ans);
}

int main(){ int T = read(); while(T --) Work(); return 0; }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章