需要拆点,即把每一天拆成没用过餐巾和和用完的餐巾(不要在意语法错误)
把S向每天的废餐巾连一条费用为零,流量为r[i]的边,表示当天产生r[i]个脏餐巾。
DAYi 的脏餐巾向DAYi+1的脏餐巾连一条费用为0,流量为inf的边,表示把这一天的脏餐巾留到下一天处理
把每天的好餐巾向T连一条费用为0,流量为r[i]的边,表示这一天用废了r[i]条餐巾
因为快洗,慢洗总量要求相同,所以不用分开考虑。
我就和着写了,把每天脏餐巾向洗完的天连一条费用为洗的花费,流量为inf的边,
从S向每天新餐巾连一条流量inf,费用p的边,表示每天都可以买新餐巾。
反遍怎么建略。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<queue> #define inf 100000000 using namespace std; int day,kuai[205],p,m,f,n,s; int S,T; int adj[1000],from[1000],dis[1000],flag[1000],e=2; struct node { int v,next,l,f; } a[10000]; void add(int u,int v,int l,int f) {a[e].v=v;a[e].next=adj[u];a[e].f=f;a[e].l=l;adj[u]=e++;} int bfs() { for(int i=S+1;i<=T;i++) dis[i]=inf; dis[S]=0; queue<int> q; flag[S]=1; q.push(S); while(!q.empty()) { int x=q.front();q.pop();flag[x]=0;//cout<<x<<" "; for(int i=adj[x];i;i=a[i].next) { int to=a[i].v;//cout<<to<<" "; if(a[i].l&&dis[to]>dis[x]+a[i].f) { dis[to]=dis[x]+a[i].f; if(!flag[to]) { q.push(to); flag[to]=1; } from[to]=i; } } } if(dis[T]==inf)return 0; return dis[T]; } int dfs() { int aa=T,bb=inf; while(aa!=S) { bb=min(bb,a[from[aa]].l); aa=a[from[aa]^1].v; } aa=T; while(aa!=S) { a[from[aa]].l-=bb; a[from[aa]^1].l+=bb; aa=a[from[aa]^1].v; } return bb; } int yjn() { freopen("napkin.in","r",stdin); freopen("napkin.out","w",stdout); //memset(adj,-1,sizeof(adj)); scanf("%d",&day); for(int i=1;i<=day;i++) scanf("%d",&kuai[i]); S=0,T=day*2+1; scanf("%d%d%d%d%d",&p,&m,&f,&n,&s); for(int i=1;i<=day;i++) { add(S,i,kuai[i],0);add(i,S,0,0); add(i+day,T,kuai[i],0);add(T,i+day,0,0); if(i+1<=day)add(i,i+1,inf,0),add(i+1,i,0,0); if(i+m<=day)add(i,i+day+m,inf,f),add(i+day+m,i,0,-f); if(i+n<=day)add(i,i+day+n,inf,s),add(i+day+n,i,0,-s); add(S,i+day,inf,p);add(i+day,S,0,-p); } int ans=0,l; while(l=bfs()) ans+=l*dfs(); cout<<ans; } int qty=yjn(); int main(){;}