[bzoj1221]软件开发
记源点为S,汇点为T,第i天裂成两个点,分别是i1和i2,表示剩余的毛巾(都是脏毛巾,因为一定可以做到每天不剩余干净的毛巾)和使用的毛巾(用来保证最大流符合条件),然后考虑以下边:
1.S向每一个i1连一条(ni,0)的边,表示用过的毛巾;
2.i2向每一个T连一条(ni,0)的边,表示消耗毛巾;
3.每一个i1向(i+1)1连一条(inf,0)的边,表示剩余毛巾的传递;
4.S向每一个i2连一条(ni/inf,F)的边,表示买毛巾;
5.每一个i1向(i+a+1)2连一条(inf,Fa)的边,表示用a方法洗毛巾;
6.每一个i1向(i+b+1)2连一条(inf,Fb)的边,表示用b方法洗毛巾。
这样就可以处理好所有问题,跑最小费用最大流即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2005 4 #define oo 0x3f3f3f3f 5 struct ji{ 6 int nex,to,len,cost; 7 }edge[N*10]; 8 queue<int>q; 9 int E,n,a,b,f,fa,fb,t,head[N],from[N],d[N],vis[N]; 10 void add(int x,int y,int z,int w){ 11 edge[E].nex=head[x]; 12 edge[E].to=y; 13 edge[E].len=z; 14 edge[E].cost=w; 15 head[x]=E++; 16 if (E&1)add(y,x,0,-w); 17 } 18 bool spfa(){ 19 memset(vis,0,sizeof(vis)); 20 memset(d,oo,sizeof(d)); 21 d[0]=0; 22 q.push(0); 23 while (!q.empty()){ 24 int k=q.front(); 25 q.pop(); 26 vis[k]=0; 27 for(int i=head[k];i!=-1;i=edge[i].nex){ 28 int v=edge[i].to; 29 if ((edge[i].len)&&(d[v]>d[k]+edge[i].cost)){ 30 d[v]=d[k]+edge[i].cost; 31 from[v]=i; 32 if (!vis[v]){ 33 vis[v]=1; 34 q.push(v); 35 } 36 } 37 } 38 } 39 return d[t]<oo; 40 } 41 int dinic(){ 42 int ans=0; 43 while (spfa()){ 44 int len=oo; 45 for(int i=t;i;i=edge[from[i]^1].to)len=min(len,edge[from[i]].len); 46 ans+=len*d[t]; 47 for(int i=t;i;i=edge[from[i]^1].to){ 48 edge[from[i]].len-=len; 49 edge[from[i]^1].len+=len; 50 } 51 } 52 return ans; 53 } 54 int main(){ 55 scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb); 56 memset(head,-1,sizeof(head)); 57 for(int i=1;i<=n;i++){ 58 scanf("%d",&t); 59 add(0,i,t,0); 60 add(0,i+n,t,f); 61 add(i+n,2*n+1,t,0); 62 if (i<n)add(i,i+1,oo,0); 63 if (i+a<n)add(i,i+a+n+1,oo,fa); 64 if (i+b<n)add(i,i+b+n+1,oo,fb); 65 } 66 t=2*n+1; 67 printf("%d",dinic()); 68 }