최적화 경사 DP (연구 노트)

예배 요약 YYB 갱스

보드의 최적화의 기울기 위 YYB 갱스이 매우 분명하게하기 때문에, 그래서 나는 그들을 반복하지 않을 것이다. 템플릿 질문에 그것의 여러 세트 볼 것이다.

파란색 책과 장 "작업 일정"을 통해 마련하는 것입니다이 질문은 진보적 인 층 경사 최적화를 설명하는 예입니다.

로스는 경사 최적화를 살 수 끈적 거리는의 버전을하지 약화

경사 최적화 템플릿 : POJ에 일반 판

향상된 BZOJ 버전 : 경사 최적화 + 반

질문의 의미 : N 작업, 각 작업에 필요한 완료 시간이 \ (t_i \) , 여러 일괄 처리로 구분이 N 작업을 시도 작업이 시작되기 전에 각 배치는, 기계가 시간 S를 시작해야 이러한 작업이 완료된다 각 작업에 요하는 시간은 시간 합 (작업 동일한 수 동시에 완료하기 위해). 작업 완료 시간 당 비용 계수를 곱한 값의 비용 소요 \ (C_I \) . 최소 전체 비용을 찾기.

세트 \ ([I]가 \ F) 의 사용에 대한 최소 비용의 여러 배치로 전면을 나타내는 I 일괄 작업 "사전 수수료 계산은"아이디어는 다음 전사 식을 갖는다 :

\ (F [i]를 min_ = {0 <J = <I} [J] + F SUMT [I] * (sumc [I] -sumc [J]) + S *의 (sumc [N] -sumc [J] ) \)

루오는에서만 끈적 거리는했다 \ (N ^ 2 \) 사례 :

const int N=5005;
int sumt[N],sumc[N],f[N];
int main(){
    int n=read(),S=read();
    for(int i=1;i<=n;i++){
        int t=read(),c=read();
        sumt[i]=sumt[i-1]+t;
        sumc[i]=sumc[i-1]+c;
    }
    memset(f,0x3f,sizeof(f));f[0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<i;j++)
            f[i]=min(f[i],f[j]+sumt[i]*(sumc[i]-sumc[j])+S*(sumc[n]-sumc[j]));
    printf("%d\n",f[n]);
    return 0;
}

POJ \ (\ N ^ 2) 방식은 전송 형 최적화를 고려하여 전달 될 수 없다. \ (F [I] = min_ {0 <= J <I} F [J] + SUMT [I] * (sumc [I ] -sumc [J]) + S의 * (sumc [N] -sumc [J]) \)

세트 \ (K <j 개의 \) 와 J의 K보다, 즉,

\ (F [J] + SUMT [I] * (sumc [I] -sumc [J]) + S의 * (sumc [N] -sumc [J]) <F [K] + SUMT [내가] * (sumc [I] -sumc [K])의 + S * (sumc [N] -sumc [K]) \)

이 공식을 얻을 수를 잤어요,

\ (\ FRAC {F [J] -f [K] {} sumc [J] -sumc [K]} <S + SUMT [I] \)

POJ 연습 할 수 있었다 (\) O (N) \를 :

const int N=300005;
int sumt[N],sumc[N],q[N],f[N];
int main(){
    int n=read(),S=read();
    for(int i=1;i<=n;i++){
        int t=read(),c=read();
        sumt[i]=sumt[i-1]+t;
        sumc[i]=sumc[i-1]+c;
    }
    memset(f,0x3f,sizeof(f));f[0]=0;
    int l=1,r=1;q[1]=0;
    for(int i=1;i<=n;i++){
        while(l<r&&(f[q[l+1]]-f[q[l]])<=(S+sumt[i])*(sumc[q[l+1]]-sumc[q[l]]))l++;
        f[i]=f[q[l]]+(sumt[i]*sumc[i]+S*sumc[n])-(S+sumt[i])*sumc[q[l]];
        while(l<r&&(f[q[r]]-f[q[r-1]])*(sumc[i]-sumc[q[r]])>=(f[i]-f[q[r]])*(sumc[q[r]]-sumc[q[r-1]]))r--;
        q[++r]=i;
    }
    printf("%d\n",f[n]);
    return 0;
}

주제는 강화 : 작업의 실행 시간 \ (t_i \) 음수 일 수를 나타내는 \이 (SUMT는 [내가] \) 더 이상 단조 보장, 그래서 우리는 전체 코호트를 유지해야 할 첫 번째 팀이 반드시 최선을마다하지 않습니다 위치 J를 찾기 위해, 이진 검색을 전송할 때 필요한 J 왼쪽 세그먼트의 기울기보다 작다 ([I] S + SUMT \ \) 오른쪽 세그먼트 J에서의 기울기보다 작은 \ (S + SUMT [I] \) 큰

당신은 BZOJ 접근 방식을 살 수 있습니다 :

const int N=300005;
LL sumt[N],sumc[N],q[N],f[N];
inline int erfen(int i,int j,int l,int r){
    if(l==r)return q[l];
    while(l<r){
        int mid=(l+r)>>1;
        if(f[q[mid+1]]-f[q[mid]]<=j*(sumc[q[mid+1]]-sumc[q[mid]]))l=mid+1;
        else r=mid;
    }
    return q[l];
}
int main(){
    int n=read(),S=read();
    for(int i=1;i<=n;i++){
        int t=read(),c=read();
        sumt[i]=sumt[i-1]+t;
        sumc[i]=sumc[i-1]+c;
    }
    int l=1,r=1;
    for(int i=1;i<=n;i++){
        int j=erfen(i,S+sumt[i],l,r);
        f[i]=f[j]+(sumt[i]*sumc[i]+S*sumc[n])-(S+sumt[i])*sumc[j];
        while(l<r&&(f[q[r]]-f[q[r-1]])*(sumc[i]-sumc[q[r]])>=(f[i]-f[q[r]])*(sumc[q[r]]-sumc[q[r-1]]))r--;
        q[++r]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

기울기 일부 이해의 개별 최적화 : 우리는 먼저 전환 식 (경사 최적화에 나와 좋은 상태를 설정해야 타이틀을 얻기 위해 모든 사전 지식을 먼저 --- 단조로운 큐는 마스터해야 둘째 때문에는, 결국, DP의 최적화 방법 중 하나입니다. 명칭, \ (O (N-2 ^) \) , 일반적으로 용이하게 사용할 수있는 전송 방정식).

이 공식을 얻을 수있는 전송 방정식을 고려, 일반적으로 접두어를 사용하는 데 필요한 마무리 한 후, 다음 공통 루틴은 당신이에 얻을 수 있습니다, 또한 "설정 K <J와 K보다 더 J"라고 YYB 족장이다 일정한 부등식 J 및 K는, 그 기울기는 최적화 될 수있다.

그런 다음 세부 사항 중 일부는 유지 보수 시간은 확실히 보통 이중와 함수를 작성 대부분의 사람들의 크기를 비교할 것인가? 늘리거나? 접두어를 감소하고 오래 오래 열지 여부되어, 큐의 단조 로움을 유지하는 등, 자신을 이해하는 것이 필요하지만, 개인적으로 오래 오래 또 하나의 시도로, 전투 캐릭터에,이 비교 같이하여 큰 문제를 형이상학 일을 통과이 질문에 다음과 같은 "인쇄 문서"이중 생활 어려운 시간을 쓰고, 대체.

[HNOI2008] 포장 장난감 장난감

[APIO2010] 특별 행동 부대

인쇄 기사

[CEOI2004] 제재 사이트

[ZJOI2007] 창고 건축

추천

출처www.cnblogs.com/PPXppx/p/11007448.html