zoukankan      html  css  js  c++  java
  • 【HAOI2010】订货

    可以DP也可以是费用流,然而被我用非常简单的DP破了【开心】

    原题:

    某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定第一月月初的库存量为零,第n月月底的库存量也为零,问如何安排这n个月订购计划,才能使成本最低?每月月初订购,订购后产品立即到货,进库并供应市场,于当月被售掉则不必付存贮费。假设仓库容量为S。

    0<=n<=50,0<=m<=10,0<=S<=10000,0<=Ui<=10000,0<=di<=100

    恩紫萱的讲解说要用队列优化DP,我太弱没看懂,自己想出了一个我觉得比较妙的方法DP掉了

    核心思路是在买东西的时候f[i]只与f[i-1]的最优值有关(注意是最优值)

    然后要买的时候从1到S顺推,f[i]=min(f[i],f[i-1]+d[i])

    恩原理我语文不好,直接丢个图吧

    可以理解为f[i-1]代表了1到i-1所有的方案,但是都没有f[i]优,再往上考虑的话,由于增加的费用都是一样的,所以和f[1]到f[i-1]有关的方案不会优于f[i]相关的方案,就只考虑f[i]了

    如果f[i]不是更优,f[i-1]代表了f[1]到f[i-1]的方案,只管使用即可

    然后还有许多需要注意的细节(我就是因为细节问题拖了很久才A quq)

    首先货物是可以进货不入库直接卖,不占用仓库空间,所以实际上仓库有M+a[i]的储存空间(每个月的需求也可能超过仓库容量),然后每个月结束的时候f中1到M不用处理,下个月直接转移即可,但是M+1到M+a[i]这一段一定要处理成正无穷,不然会影响到下个月(我就是因为这个细节卡了一下午,差点弃疗quq)

    还有更多的细节问题,大家自己体验吧一。一

    DP代码非常短

    代码(DP):

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 int read(){int z=0,mark=1;  char ch=getchar();
     8     while(ch<'0'||ch>'9'){if(ch=='-')mark=-1;  ch=getchar();}
     9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    10     return z*mark;
    11 }
    12 const int oo=168430090;
    13 int n,m,ns;  int a[110],b[110];
    14 int f[21000];
    15 int main(){//freopen("ddd.in","r",stdin);
    16     memset(f,10,sizeof(f));
    17     cin>>n>>ns>>m;
    18     for(int i=1;i<=n;i++)  a[i]=read();
    19     for(int i=1;i<=n;i++)  b[i]=read();
    20     f[0]=0;  a[0]=0;
    21     for(int i=1;i<=n;i++){
    22         for(int j=0;j<=m;j++)  f[j]=f[j+a[i-1]]+j*ns;
    23         for(int j=m+1;j<=m+a[i-1];j++)  f[j]=oo;
    24         for(int j=1;j<=m+a[i];j++)  f[j]=min(f[j],f[j-1]+b[i]);
    25     }
    26     cout<<f[a[n]]<<endl;
    27     return 0;
    28 }
    View Code

    ======================================================下面是费用流======================================================

    至于费用流呐,建图也非常好想

    首先利用割的思想,每个月到汇一条流量为需求,费用0的边,割掉这条边表示这个月的费用满足了

    然后源到每个月一条流量正无穷,费用为这个月进货费用的边,表示物品可以随意买

    每个月到下个月一条流量为仓库容量,费用为储存话费的边,表示上个月的货可以继承到下个月

    至于我是怎么想出来的……直觉……我觉得还要继续发掘一下这其中潜在的思路规律

    代码也很简单,标准的费用流模板:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 int read(){int z=0,mark=1;  char ch=getchar();
     8     while(ch<'0'||ch>'9'){if(ch=='-')mark=-1;  ch=getchar();}
     9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    10     return z*mark;
    11 }
    12 const int oo=168430090;
    13 struct ddd{int next,y,evalue,rev,cost;}e[1100000];  int LINK[510000],ltop=0;
    14 inline void insert(int x,int y,int z,int _cost){
    15     e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;e[ltop].evalue=z;e[ltop].rev=ltop+1;e[ltop].cost=_cost;
    16     e[++ltop].next=LINK[y];LINK[y]=ltop;e[ltop].y=x;e[ltop].evalue=0;e[ltop].rev=ltop-1;e[ltop].cost=-_cost;
    17 }
    18 int n,m,ns;  int s,t;
    19 int dist[510000];
    20 int QUEUE[510000],head=0;  bool visited[510000];
    21 int last[510000],last_e[510000];
    22 bool spfa(){
    23     memset(visited,0,sizeof(visited));
    24     memset(dist,10,sizeof(dist));
    25     QUEUE[head=1]=s;  dist[s]=0;
    26     for(int k=1;k<=head;k++){
    27         for(int i=LINK[QUEUE[k]];i;i=e[i].next)
    28             if(e[i].evalue && dist[QUEUE[k]]+e[i].cost<dist[e[i].y]){
    29                 dist[e[i].y]=dist[QUEUE[k]]+e[i].cost;
    30                 last[e[i].y]=QUEUE[k],last_e[e[i].y]=i;
    31                 if(!visited[e[i].y])  QUEUE[++head]=e[i].y,visited[e[i].y]=true;
    32             }
    33         visited[QUEUE[k]]=false;
    34     }
    35     return dist[t]<oo;
    36 }
    37 int cost_flow(){
    38     int bowl=0;
    39     while(spfa()){
    40         int min_flow=oo;
    41         for(int i=t;i!=s;i=last[i])  min_flow=min(min_flow,e[last_e[i]].evalue);
    42         for(int i=t;i!=s;i=last[i]){
    43             bowl+=min_flow*e[last_e[i]].cost;
    44             e[last_e[i]].evalue-=min_flow,e[e[last_e[i]].rev].evalue+=min_flow;
    45         }
    46     }
    47     return bowl;
    48 }
    49 int main(){//freopen("ddd.in","r",stdin);
    50     cin>>n>>ns>>m;  s=0,t=n+1;
    51     for(int i=1;i<=n;i++)  insert(i,t,read(),0);
    52     for(int i=1;i<=n;i++)  insert(s,i,oo,read());
    53     for(int i=1;i<n;i++)  insert(i,i+1,m,ns);
    54     cout<<cost_flow()<<endl;
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    Postman使用教程
    CAD和ArcGIS转换 矢量配准
    SAP CRM Advanced search和Simple search里Max hit表现行为的差异
    SAP CRM Product simple search的启用步骤
    如何快速定位SAP CRM订单应用(Order Application)错误消息抛出的准确位置
    如何动态修改SAP CRM WebClient UI表格栏的宽度
    如何在SAP CRM WebClient UI里创建web service并使用ABAP消费
    如何处理SAP CRM Web Service错误
    如何使用SAP CRM WebClient UI实现一个类似新浪微博的字数统计器
    如何开启SAP CRM基于WORD模板创建附件的功能
  • 原文地址:https://www.cnblogs.com/JSL2018/p/6322874.html
Copyright © 2011-2022 走看看