zoukankan      html  css  js  c++  java
  • 【Codevs1237&网络流24题】餐巾计划(费用流)

    题意:一个餐厅在相继的 N 天里,每天需用的餐巾数不尽相同。

    假设第 i 天需要 ri块餐巾(i=1,2,…,N)。餐厅可以购买新的餐巾,每块餐巾的费用为 p 分;

    或者把旧餐巾送到快洗部,洗一块需 m 天,其费用为 f 分;

    或者送到慢洗部,洗一块需 n 天(n>m),其费用为 s<f 分。
    每天结束时,餐厅必须决定将多少块脏的餐巾送到快洗部,多少块餐巾送到慢洗部,以及多少块保存起来延期送洗。

    但是每天洗好的餐巾和购买的新餐巾数之和,要满足当天的需求量。
    试设计一个算法为餐厅合理地安排好 N 天中餐巾使用计划,使总的花费最小。 
    编程找出一个最佳餐巾使用计划。

    思路:RYZ作业

    费用流经典模型之一

    BYVOID:

    【建模方法】
    把每天分为二分图两个集合中的顶点Xi,Yi,建立附加源S汇T。
    1、从S向每个Xi连一条容量为ri,费用为0的有向边。
    2、从每个Yi向T连一条容量为ri,费用为0的有向边。
    3、从S向每个Yi连一条容量为无穷大,费用为p的有向边。
    4、从每个Xi向Xi+1(i+1<=N)连一条容量为无穷大,费用为0的有向边。
    5、从每个Xi向Yi+m(i+m<=N)连一条容量为无穷大,费用为f的有向边。
    6、从每个Xi向Yi+n(i+n<=N)连一条容量为无穷大,费用为s的有向边。
    求网络最小费用最大流,费用流值就是要求的最小总花费。
    【建模分析】
    这个问题的主要约束条件是每天的餐巾够用,而餐巾的来源可能是最新购买,也可能是前几天送洗,

    今天刚刚洗好的餐巾。每天用完的餐巾可以选择送到快洗部或慢洗部,或者留到下一天再处理。
    经过分析可以把每天要用的和用完的分离开处理,建模后就是二分图。

    二分图X集合中顶点Xi表示第i天用完的餐巾,其数量为ri,所以从S向Xi连接容量为ri的边作为限制

    Y集合中每个点Yi则是第i天需要的餐巾,数量为ri,与T连接的边容量作为限制。

    每天用完的餐巾可以选择留到下一天(Xi->Xi+1),不需要花费,

    送到快洗部(Xi->Yi+m),费用为f,

    送到慢洗部(Xi->Yi+n),费用为s。

    每天需要的餐巾除了刚刚洗好的餐巾,还可能是新购买的(S->Yi),费用为p。

    在网络上求出的最小费用最大流,满足了问题的约束条件(因为在这个图上最大流一定可以使与T连接的边全部满流,其他边只要有可行流就满足条件),

    而且还可以保证总费用最小,就是我们的优化目标。

     UPD(19.10.29):Xi之间和Yi之间没有边是因为他们分别和S,T连接的边已经等价于每天使用ri了

      1 var head,vet,next,len1,len2,fan:array[1..2100000]of longint;
      2     inq:array[1..5000]of boolean;
      3     q:array[0..5000]of longint;
      4     num,pre:array[1..5000,1..2]of longint;
      5     dis,a:array[1..5000]of longint;
      6     n,m,p1,m1,f1,n1,s1,ans,source,src,s,tot,i,j:longint;
      7 
      8 function min(x,y:longint):longint;
      9 begin
     10  if x<y then exit(x);
     11  exit(y);
     12 end;
     13 
     14 procedure add(a,b,c,d:longint);
     15 begin
     16  inc(tot);
     17  next[tot]:=head[a];
     18  vet[tot]:=b;
     19  len1[tot]:=c;
     20  len2[tot]:=d;
     21  head[a]:=tot;
     22 
     23  inc(tot);
     24  next[tot]:=head[b];
     25  vet[tot]:=a;
     26  len1[tot]:=0;
     27  len2[tot]:=-d;
     28  head[b]:=tot;
     29 end;
     30 
     31 function spfa:boolean;
     32 var u,e,v,i,t,w:longint;
     33 begin
     34  for i:=1 to s do
     35  begin
     36   dis[i]:=maxlongint>>1;
     37   inq[i]:=false;
     38  end;
     39  t:=0; w:=1; q[1]:=source; dis[source]:=0; inq[source]:=true;
     40  while t<w do
     41  begin
     42   inc(t); u:=q[t mod 5000]; inq[u]:=false;
     43   e:=head[u];
     44   while e<>0 do
     45   begin
     46    v:=vet[e];
     47    if (len1[e]>0)and(dis[u]+len2[e]<dis[v]) then
     48    begin
     49     dis[v]:=dis[u]+len2[e];
     50     pre[v,1]:=u;
     51     pre[v,2]:=e;
     52     if not inq[v] then
     53     begin
     54      inc(w); q[w mod 5000]:=v; inq[v]:=true;
     55     end;
     56    end;
     57    e:=next[e];
     58   end;
     59  end;
     60  if dis[src]=maxlongint>>1 then exit(false);
     61  exit(true);
     62 end;
     63 
     64 procedure mcf;
     65 var k,e,t:longint;
     66 begin
     67  k:=src; t:=maxlongint;
     68  while k<>source do
     69  begin
     70   t:=min(t,len1[pre[k,2]]);
     71   k:=pre[k,1];
     72  end;
     73  k:=src;
     74  while k<>source do
     75  begin
     76   e:=pre[k,2];
     77   len1[e]:=len1[e]-t;
     78   len1[fan[e]]:=len1[fan[e]]+t;
     79   ans:=ans+t*len2[e];
     80   k:=pre[k,1];
     81  end;
     82 end;
     83 
     84 begin
     85  assign(input,'codevs1237.in'); reset(input);
     86  assign(output,'codevs1237.out'); rewrite(output);
     87  readln(n,p1,m1,f1,n1,s1);
     88  for i:=1 to 2100000 do
     89   if i and 1=1 then fan[i]:=i+1
     90    else fan[i]:=i-1;
     91  for i:=1 to n do read(a[i]);
     92  for i:=1 to n do
     93   for j:=1 to 2 do
     94   begin
     95    inc(s); num[i,j]:=s;
     96   end;
     97  source:=s+1; src:=s+2; s:=s+2;
     98  for i:=1 to n do add(source,num[i,1],a[i],0);
     99  for i:=1 to n do add(num[i,2],src,a[i],0);
    100  for i:=1 to n-1 do add(num[i,1],num[i+1,1],maxlongint,0);
    101  for i:=1 to n do add(source,num[i,2],maxlongint,p1);
    102  for i:=1 to n do
    103   if i+m1<=n then add(num[i,1],num[i+m1,2],maxlongint,f1);
    104  for i:=1 to n do
    105   if i+n1<=n then add(num[i,1],num[i+n1,2],maxlongint,s1);
    106  while spfa do mcf;
    107  writeln(ans);
    108  close(input);
    109  close(output);
    110 end.
  • 相关阅读:
    滑雪
    CSS被误删了 心态炸了。
    About Me
    偶数个3|递归|递推
    luogu P3200 [HNOI2009]有趣的数列|Catalan数|数论
    Sumdiv|同余|约数|拓展欧几里得算法
    博弈论
    友链——大佬们的博客
    【翻译】PalmOS 的PDB格式文件
    用acme.sh给ssl证书续期
  • 原文地址:https://www.cnblogs.com/myx12345/p/6508934.html
Copyright © 2011-2022 走看看