zoukankan      html  css  js  c++  java
  • POJ 1180 Batch Scheduling

    $dp$,斜率优化。

    有一种很直观的$dp$方式:

    设$dp[j][i]$表示前$i$个数字,分成了$j$组的最小代价。$dp$转移方程很容易写,斜率优化也很容易。斜率优化之后时间复杂度为$O(n^2)$,最坏情况大约是是$5000$万的复杂度。我尝试了一下,但是不幸超时了。但是当我特判掉$s=0$的情况(该情况肯定是分成$n$组)之后,去尝试分$1000$组,$500$组,$250$组......能否$AC$,最终发现后台数据除去$s=0$的情况之后,最坏的情况是分成$166$组就可以得到最优解。因此这样$500ms$水过去了。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-10;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    template <class T>
    inline void read(T &x)
    {
        char c = getchar();
        x = 0;
        while(!isdigit(c)) c = getchar();
        while(isdigit(c))
        {
            x = x * 10 + c - '0';
            c = getchar();
        }
    }
    
    int dp[2][10010];
    int n,s;
    int q[10010],f1,f2;
    int sumT[10010],sumF[10010];
    int flag;
    int ans;
    
    bool delete1(int t,int a,int b,int c)
    {
        if(
            dp[flag^1][b]-(t+1)*s*sumF[b]-sumT[c]*sumF[b]<=
            dp[flag^1][a]-(t+1)*s*sumF[a]-sumT[c]*sumF[a]
        ) return 1;
        return 0;
    }
    
    bool delete2(int t,int a,int b,int c)
    {
        if(
            ((dp[flag^1][c]-(t+1)*s*sumF[c])-(dp[flag^1][b]-(t+1)*s*sumF[b]))*(sumF[b]-sumF[a])<=
            ((dp[flag^1][b]-(t+1)*s*sumF[b])-(dp[flag^1][a]-(t+1)*s*sumF[a]))*(sumF[c]-sumF[b])
        ) return 1;
        return 0;
    }
    
    int main()
    {
        scanf("%d%d",&n,&s);
    
        for(int i=1; i<=n; i++)
        {
            int tt,ff;
            scanf("%d%d",&tt,&ff);
            sumT[i]=sumT[i-1]+tt;
            sumF[i]=sumF[i-1]+ff;
        }
    
        if(s==0)
        {
            ans=0;
            for(int i=1; i<=n; i++) ans=ans+sumT[i]*(sumF[i]-sumF[i-1]);
            printf("%d
    ",ans);
            return 0;
        }
    
        flag=0;
        ans=0x7FFFFFFF;
    
        for(int i=1; i<=n; i++) dp[flag][i]=(sumT[i]+s)*sumF[i];
        ans=min(ans,dp[flag][n]);
    
        for(int j=2; j<=min(166,n); j++)
        {
            flag=flag^1;
            f1=f2=0;
            q[0]=j-1;
            for(int i=j; i<=n; i++)
            {
                while(1)
                {
                    if(f2-f1+1<2) break;
                    if(delete1(j-1,q[f1],q[f1+1],i)) f1++;
                    else break;
                }
    
                dp[flag][i]=dp[flag^1][q[f1]]+(j*s+sumT[i])*(sumF[i]-sumF[q[f1]]);
    
                while(1)
                {
                    if(f2-f1+1<2) break;
                    if(delete2(j-1,q[f2-1],q[f2],i)) f2--;
                    else break;
                }
    
                f2++;
                q[f2]=i;
            }
            ans=min(ans,dp[flag][n]);
        }
    
        printf("%d
    ",ans);
        
        return 0;
    }
    View Code

    水过去的方法当然是不可取的,复杂度太高了。看了神犇博客,发现这题可以$O(n)$做。

    设$dp[i]$表示以$i$为任务起点,到达终点的最小代价。

    那么,$dp[i]=min(dp[x]+(sumF[n]-sumF[i-1])*(s+sumT[x-1]-sumT[i-1]))$。

    进行斜率优化之后时间复杂度降到了$O(n)$。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    const double pi=acos(-1.0),eps=1e-10;
    void File()
    {
        freopen("D:\in.txt","r",stdin);
        freopen("D:\out.txt","w",stdout);
    }
    template <class T>
    inline void read(T &x)
    {
        char c = getchar();
        x = 0;
        while(!isdigit(c)) c = getchar();
        while(isdigit(c))
        {
            x = x * 10 + c - '0';
            c = getchar();
        }
    }
    
    int n,s;
    int T[10010],F[10010],dp[10010];
    int sumT[10010],sumF[10010];
    int f1,f2,q[10010];
    
    bool delete1(int a,int b,int c)
    {
        int A=sumF[n]-sumF[c-1];
        if(dp[a]+A*sumT[a-1]>=dp[b]+A*sumT[b-1]) return 1;
        return 0;
    }
    
    bool delete2(int a,int b,int c)
    {
        if((dp[b]-dp[a])*(sumT[c-1]-sumT[b-1])<=
           (dp[c]-dp[b])*(sumT[b-1]-sumT[a-1])) return 1;
        return 0;
    }
    
    int main()
    {
        scanf("%d%d",&n,&s);
    
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&T[i],&F[i]);
            sumT[i]=sumT[i-1]+T[i];
            sumF[i]=sumF[i-1]+F[i];
        }
    
        f1=f2=0; q[0]=n+1;
        for(int i=n;i>=1;i--)
        {
            while(1)
            {
                if(f2-f1+1<2) break;
                if(delete1(q[f1],q[f1+1],i)) f1++;
                else break;
            }
    
            dp[i]=dp[q[f1]]+(sumF[n]-sumF[i-1])*(s+sumT[q[f1]-1]-sumT[i-1]);
    
            while(1)
            {
                if(f2-f1+1<2) break;
                if(delete2(q[f2-1],q[f2],i)) f2--;
                else break;
            }
    
            f2++;
            q[f2]=i;
        }
    
        printf("%d
    ",dp[1]);
    
        return 0;
    }
  • 相关阅读:
    Qt:移动无边框窗体(使用Windows的SendMessage)
    github atom 试用
    ENode框架Conference案例转载
    技术
    NET 领域驱动设计实战系列总结
    mac 配置Python集成开发环境
    User、Role、Permission数据库设计ABP
    Oracle 树操作
    Oracle 用户权限管理方法
    Web Api 2, Oracle and Entity Framework
  • 原文地址:https://www.cnblogs.com/zufezzt/p/6358802.html
Copyright © 2011-2022 走看看