【網路流二十四題】餐巾計劃
阿新 • • 發佈:2021-07-29
題目
解析:
二分圖。\(X\)集合中的\(x_i\)表示第\(i\)天用掉的餐巾數量,\(Y\)集合中的\(y_i\)表示第\(i\)天需要的餐巾。建圖時,從源點\(s\)向集合\(X\)中的每一個點連一條容量為\(r_i\)的邊,從集合\(Y\)中的每一個點向匯點\(t\)連一條容量\(r_i\)的邊來限制第\(i\)天用的餐巾。每天用完的餐巾有以下四個去向:
- 選擇留到下一天\(x_i->x_{i+1}\),花費為\(0\)。
- 送到快洗部\(x_i->y_{i+d1}\),費用為\(c1\)。
- 送到慢洗部\(x_i->y_{i+d2}\),費用為\(c2\)。
- 每天需要的餐巾除了剛剛洗好的餐巾,還可能是新購買的\(s->y_i\)
建完圖後跑一邊費用流即可。
code:
#include <bits/stdc++.h> using namespace std; const int Maxn=2005; const int Maxm=6000; const int inf=0x3f3f3f; int n,m,s,t,c,d1,c1,d2,c2,size=-1,x,sum; int first[Maxn],tmp[Maxn],dis[Maxn],vis[Maxn]; struct shu{int to,next,l,c;}e[Maxm<<1]; inline int get_int() { int x=0,f=1;char c; for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar()); if(c=='-') f=-1,c=getchar(); for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0'; return x*f; } inline int min(int x,int y){return x>y ? y : x;} inline void add(int x,int y,int l,int c) { e[++size].next=first[x],first[x]=size,e[size].to=y,e[size].l=l,e[size].c=c; } inline void init() { n=get_int(),c=get_int(),d1=get_int(),c1=get_int(),d2=get_int(),c2=get_int(); s=0,t=2*n+1; for(int i=s;i<=t;i++) first[i]=-1; for(int i=1;i<=n;i++) { x=get_int(); add(s,i,x,0),add(i,s,0,0); add(n+i,t,x,0),add(t,n+i,0,0); if(i+n+d1<=2*n) add(i,i+n+d1,inf,c1),add(i+n+d1,i,0,-c1); if(i+n+d2<=2*n) add(i,i+n+d2,inf,c2),add(i+n+d2,i,0,-c2); if(i<n) add(i,i+1,inf,0),add(i+1,i,0,0); add(s,i+n,inf,c),add(i+n,s,0,-c); } } inline bool spfa() { queue<int>q; for(int i=s;i<=t;i++) dis[i]=inf,tmp[i]=first[i]; dis[s]=0,q.push(s),vis[s]=1; while(q.size()) { int p=q.front();q.pop();vis[p]=0; for(register int u=first[p];~u;u=e[u].next) { int to=e[u].to; if(!e[u].l || dis[to]<=dis[p]+e[u].c) continue; dis[to]=dis[p]+e[u].c; if(!vis[to]) q.push(to),vis[to]=1; } } return dis[t]!=inf; } inline int dfs(int p,int flow) { if(p==t) return flow; int s=0;vis[p]=1; for(register int &u=tmp[p];~u;u=e[u].next) { int to=e[u].to; if(vis[to] || dis[to]!=dis[p]+e[u].c || !e[u].l) continue; int minn=dfs(to,min(flow-s,e[u].l)); s+=minn,e[u].l-=minn,e[u^1].l+=minn,sum+=minn*e[u].c; if(s==flow) break; } vis[p]=0; return s; } inline void solve() { while(spfa()) {while(x=dfs(s,inf));} cout<<sum; } int main() { init(); solve(); return 0; }