斜率优化(凸包优化)DP问题acm

斜率优化(凸包优化)Dp

  • #写在前面
    • ##任务安排1
      • ----c++版
    • ##任务安排2
      • ----c++版
    • ##任务安排3
      • ----c++版
    • ##运输小猫
      • ----c++版


#写在前面

这类问题做的过程比较偏数学

对于状态转移方程需要经过一些数学上的整理

之后几道题步步深入斜率优化问题

##任务安排1

https://www.acwing.com/problem/content/302/
斜率优化(凸包优化)DP问题acm_第1张图片

----c++版

#include
#include
using namespace std;
#include
const int N=5010;
int n,s;
int sumt[N],sumc[N];
int f[N];
int q[N];

int main(){
     
    scanf("%d%d", &n, &s);
    for(int i=1; i<=n; i++){
     
        int t, c;
        scanf("%d%d", &t, &c);
        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;
}

##任务安排2

https://www.acwing.com/problem/content/303/

这题仅仅是数据范围扩大了

斜率优化(凸包优化)DP问题acm_第2张图片

----c++版

#include
#include
#include
using namespace std;

typedef long long ll;

const int N=300010;
int n,s;
ll c[N], t[N];
ll f[N];
int q[N];

int main(){
     
    scanf("%d%d", &n, &s);
    for(int i=1; i<=n; i++){
     
        scanf("%lld%lld", &t[i], &c[i]);
        t[i]+=t[i-1];
        c[i]+=c[i-1];
    }
    
    int hh=0, tt=0;
    q[0]=0;//f[0]也是一个可选答案
    for(int i=1; i<=n; i++){
     
        //队列中至少有两个数
        while(hh < tt && (f[q[hh+1]]-f[q[hh]]) <= (t[i]+s)*(c[q[hh+1]]-c[q[hh]])) hh++;
        int j = q[hh]; //对头,即第一个斜率大于当前斜率的点
        f[i] = f[j]-(t[i]+s)*c[j]+t[i]*c[i]+s*c[n];
        while(hh < tt && (f[q[tt]]-f[q[tt-1]])*(c[i]-c[q[tt]]) >= (f[i]-f[q[tt]])*(c[q[tt]]-c[q[tt-1]]))
            tt--;//去掉队尾的
        q[++tt] = i;
    }
    
    printf("%lld", f[n]);
    
    return 0;
}

##任务安排3

https://www.acwing.com/problem/content/304/

与上一题唯一的区别就是 t 可能是负数了
斜率优化(凸包优化)DP问题acm_第3张图片

----c++版

#include
#include
using namespace std;
const int N=300010;
typedef long long ll;

int n,s;
ll t[N],c[N];
ll f[N];
int q[N];

int main(){
     
    scanf("%d%d", &n, &s);
    for(int i=1; i<=n; i++){
     
        scanf("%lld%lld", &t[i], &c[i]);
        t[i]+=t[i-1];
        c[i]+=c[i-1];
    }
    
    int hh=0, tt=0;
    q[0]=0;
    for(int i=1;i<=n;i++){
     
        int l=hh, r=tt;
        while(l<r){
     
            int mid=l+r>>1;
            if(f[q[mid+1]]-f[q[mid]]>(t[i]+s)*(c[q[mid+1]]-c[q[mid]]))r = mid;
            else l=mid+1;
        }
        
        int j = q[r];
        f[i] = f[j]-(t[i]+s)*c[j]+t[i]*c[i]+s*c[n];
        while(hh < tt && (double)(f[q[tt]]-f[q[tt-1]])*(c[i]-c[q[tt-1]]) >= (double)(f[i]-f[q[tt-1]])*(c[q[tt]]-c[q[tt-1]]))
            tt--;//去掉队尾的
        q[++tt] = i;
    }
    
    printf("%lld", f[n]);
    
    return 0;
}

##运输小猫

https://www.acwing.com/problem/content/305/

斜率优化(凸包优化)DP问题acm_第4张图片

----c++版

#include
#include
#include
using namespace std;

typedef long long ll;

const int N=100010, M=100010, P=110;

int n,m,p;
ll d[N], t[N], a[N], s[N];
ll f[P][M];
int q[M];

ll get_y(int k, int j){
     
    return f[j-1][k]+s[k];
}

int main(){
     
    scanf("%d%d%d", &n,&m,&p);
    for(int i=2; i<=n; i++){
     
        scanf("%lld", &d[i]);
        d[i]+=d[i-1];
    }
    
    for(int i=1; i<=m; i++){
     
        int h;
        scanf("%d%lld", &h, &t[i]);
        a[i] = t[i]-d[h];//直接过滤掉了其他的山,只剩下留小猫的
    }
    
    sort(a+1, a+m+1);
    
    for(int i=1; i<=m; i++)s[i]=s[i-1]+a[i];
    
    memset(f, 0x3f, sizeof f);
    
    for(int j=0; j<=p; j++) f[j][0] = 0;//j个饲养员处理0只小猫都是0
    
    for(int j=1; j<=p; j++){
     
        int hh=0, tt=0;
        q[0] = 0;
        for(int i=1;i<=m;i++){
     
            while(hh<tt && (get_y(q[hh+1],j)-get_y(q[hh],j))<=a[i]*(q[hh+1]-q[hh]))hh++;
            int k = q[hh];
            f[j][i] = f[j-1][k]-a[i]*k+s[k]+a[i]*i-s[i];
            while(hh<tt && (get_y(q[tt],j)-get_y(q[tt-1],j))*(i-q[tt])>=
                    (get_y(i,j)-get_y(q[tt],j))*(q[tt]-q[tt-1]))tt--;
            q[++tt]=i;
        }
    }
    
    printf("%lld", f[p][m]);
    return 0;
}

你可能感兴趣的:(算法模板,算法,凸包,c++,动态规划,acm)