• [JZOJ P1327] [DP]订货


    啊这是一道省选题,怪不得我不会写,最重要的是战胜自己的内心要坚信你会写出来,恩。

    用f[i][j]来表示前i个月还有j吨货的费用,就是依靠 上一月的费用+上一月的货的存费+订需要的+订(j-k)的费用

    f[i][j]=min(f[i-1][k]+k*m+d[i]*(u[i]+(j-k)));  ( 0<j,k<s)  ->      f[i][j]=min(f[i-1][k]-d[i]*k+k*m)+d[i]*(u[i]+j);

    由于k的范围是从0到s 而s大的不止一点,所以一步步循环就会超时,因此需要用队列来优化,跟 超级教主 相似,都是单调递减,队首为最优 之后一步步把队尾踢出去换最优。

    由于超级教主都是固定的值,而这玩意你只能确定每一回的值,因此需要做N遍超级教主!

    先确定f[i][0] 因此就要补充,-> 上一月的存货k<这个月的需要  来算出上一月的+补充=需要的 最优。

    之后为了下一月的f[i][0] 就要提前算出这个月的f[i][j]各种情况 因此再有 上一月的存货k<s  队首最优,算出f[i][j]

    答案就为f[n][0]。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n,m,s,u[55],d[55];
    int f[52][10010],que[100010];
    int head=0,tail=0;
    void work(int i,int k)
    {
        while(head<tail&&(f[i-1][k]+k*(m-d[i])<f[i-1][que[tail-1]]+que[tail-1]*(m-d[i])))
            tail--;
        que[tail++]=k;
    }
    int main()
    {
    cin>>n>>m>>s;
        for(int i=1;i<=n;i++)    cin>>u[i];
        for(int i=1;i<=n;i++)    cin>>d[i];
        memset(f,10,sizeof(f));
        f[0][0]=0;
        for(int i=1;i<=n;i++)
        {
            head=tail=0;
            for(int k=0;k<=u[i];k++)    work(i,k);
            int t=que[head];
            f[i][0]=f[i-1][t]+t*(m-d[i])+d[i]*u[i];
            for(int j=1;j<=s;j++)
            {
                if(j+u[i]<=s)    work(i,j+u[i]);
                int k=que[head];
                f[i][j]=f[i-1][k]+k*m+d[i]*(u[i]+j-k);
            }
        }
        cout<<f[n][0];
    return 0;
    }
    你好蠢居然还要看code

    调试时莫名出现输入输出,一个bug吧,这道题队列应该是最优解法,然而姬树流大大早已想出简单DP,然而看不懂,还有一个做法是费用流,费用流是什么鬼。以后补上。

    No matter how you feel, get up , dress up , show up ,and never give up.
  • 相关阅读:
    Windows下MySQL8.0.23的下载与安装简单易用
    【转】decimal double的区别
    【转】.NET垃圾回收
    vs2010 断点调试故障 反编译插件引起的
    【摘】别人对面向对象的理解
    【转】C# indexof
    【转】八大排序算法总结
    【转】JS windows.open()详解
    【转】with as
    【转】SQL Server的几种约束
  • 原文地址:https://www.cnblogs.com/Kaike/p/6323447.html
Copyright © 2020-2023  润新知