题意:一共有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\n",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(之前就没有统计进去)。
跑最小费用流即可。