zoukankan      html  css  js  c++  java
  • CF802C Heidi and Library(hard)

    题意:一共有n天每天一个请求,要求借一本书,即刻归还。图书馆中最多存k本书,多了就要扔掉。第i本书的价格为c[i]。问满足所有请求的最小买书花费?

    n<=200。

    标程:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=205;
     4 const int inf=0x3f3f3f3f;
     5 struct node{int to,next,w,c;}num[N*10];
     6 queue<int> q;
     7 int cnt=1,sc,S,T,dis[N],head[N],n,a[N],c[N],ans,k,pre[N],prevv[N],preve[N],t[1000005];
     8 void add(int x,int y,int w,int c)
     9 {num[++cnt].to=y;num[cnt].next=head[x];num[cnt].w=w;num[cnt].c=c;head[x]=cnt;
    10 num[++cnt].to=x;num[cnt].next=head[y];num[cnt].w=-w;num[cnt].c=0;head[y]=cnt;}
    11 
    12 void build()
    13 {
    14     for (int i=1;i<n;i++) add(i,i+1,0,k-1);
    15     for (int i=1;i<=n;i++)
    16       if (pre[i]&&pre[i]!=i-1)
    17       {
    18             add(S,pre[i]+1,0,1);
    19             add(pre[i]+1,++sc,0,1);
    20             add(i,sc,-c[a[i]],1);
    21             add(sc,T,0,1);
    22       }
    23 }
    24 void spfa()
    25 {
    26     q.push(S);memset(dis,inf,sizeof(dis));
    27     dis[S]=0;
    28     while (!q.empty())
    29     {
    30         int now=q.front();q.pop();
    31         for (int i=head[now];i;i=num[i].next)
    32           if (num[i].c&&dis[num[i].to]>dis[now]+num[i].w)
    33           {
    34                 dis[num[i].to]=dis[now]+num[i].w,q.push(num[i].to);
    35                 prevv[num[i].to]=now;preve[num[i].to]=i;
    36           }
    37             
    38     }
    39 }
    40 void solve()
    41 {
    42     while (1==1)
    43     {
    44        spfa();
    45        if (dis[T]==inf) break;
    46        int sum=0;
    47        for (int i=T,it;i!=S;i=prevv[i]) 
    48           it=preve[i],sum+=num[it].w,num[it].c--,num[it^1].c++;
    49        ans+=sum;
    50     } 
    51 }
    52 int main()
    53 {
    54     scanf("%d%d",&n,&k);
    55     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    56     for (int i=1;i<=n;i++) scanf("%d",&c[i]); 
    57     for (int i=1;i<=n;i++) 
    58     {
    59       pre[i]=t[a[i]];t[a[i]]=i;
    60       if (i==1||pre[i]!=i-1) ans+=c[a[i]]; 
    61     }
    62     S=n+1;T=sc=S+1;
    63     build();solve();
    64     printf("%d
    ",ans); 
    65     return 0;
    66 }

    题解:最小费用最大流

    考虑如果k=1,那么如果相邻两天的请求不相同就要重新买书,否则就可以沿用。先统计出这一部分的贡献。

    再考虑k>1还可以省下多少钱。对于表示天数的点连边如下:

    1. i和i+1连边,容量为k-1,费用为0。表示在第i天和第i+1天之间,某本书借出去的时候,图书馆中此时最多有k-1本书。

    2.如果第i天request的书和第pre[i]天一样,那么有一种选择是pre[i]天的书存储下来。

    建立辅助节点j。连边S->pre[i]+1,pre[i]+1->j,j->T,容量为1,费用为0。如果流这一条路径,相当于不保存。S->pre[i]+1,则表示第pre[i]天request的书还回来后从第pre[i]+1天开始存在书架中。

    连边i->j,容量为1,费用为-c[a[i]],如果流经这条边,说明这一天的书是之前保存下来的,不用重新买。

    注意如果i和i+1的书类是一样的,那么就不用连边pre(之前就没有统计进去)。

    跑最小费用流即可。

  • 相关阅读:
    10.16(day54)
    10.17(day55)
    10.15(day53)
    10.14(day52)
    10.12(day51)
    10.11(day50)form表单,css的引入,css选择器,css修改字体属性
    10.10(day49)初识前端,html基础
    9.25(day44)
    9.24(day43)
    9.23(day42)数据库的配置,数据库表的引擎,数据类型,约束条件
  • 原文地址:https://www.cnblogs.com/Scx117/p/9090671.html
Copyright © 2011-2022 走看看