网络流24题 餐巾纸计划
此题费用流很明显,但其难度在于建模。
首先说一下建模方式
- 先将每个点拆成两个,Xi和Yi
- 1.从源点向每个Xi连条流量为ri,0费用的边
- 2.从每个Yi向汇点连条流量为ri,0费用的边
- 3.从每个Xi向Xi+1连条流量无限,0费用的边
- 4.从每个Xi向Yi+m连流量无限,费用为f的边
5.从每个Xi向Yi+n连流量无限,费用为s的边
分析建模
- 首先你要明白每个Xi表示当天用完的餐巾的数量,Yi代表每天拥有的可用餐巾的数量,所以他们的数量显然是ri,所以有1,2连边。
- 对于每天用完的餐巾,我们可以留到下一天处理,所以有3。
还可以送到快洗部和慢洗部,所以有4,5。
代码
#include<bits/stdc++.h> using namespace std; typedef int sign; typedef long long ll; #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i) #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i) const int N=4000+5; bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;} bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;} template<typename T>T read() { T ans=0,f=1; char ch=getchar(); while(!isdigit(ch)&&ch!=‘-‘)ch=getchar(); if(ch==‘-‘)f=-1,ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-‘0‘),ch=getchar(); return ans*f; } void file() { #ifndef ONLINE_JUDGE freopen("1251.in","r",stdin); freopen("1251.out","w",stdout); #endif } int n; struct edge { int v,nex,flow,w; }e[N*N]; int head[N],cur[N],tt=1; void add(int x,int y,int flow,int w) { ++tt;e[tt].v=y;e[tt].flow=flow;e[tt].w=w;e[tt].nex=head[x];head[x]=tt; ++tt;e[tt].v=x;e[tt].flow=0;e[tt].w=-w;e[tt].nex=head[y];head[y]=tt; } int st,ed; const int inf=0x3f3f3f3f; void input() { int x; n=read<int>(); st=0;ed=2*n+1; For(i,1,n) { x=read<int>(); add(st,i,x,0); add(i+n,ed,x,0); } int p=read<int>(),m=read<int>(),f=read<int>(),nn=read<int>(),s=read<int>(); For(i,1,n) { if(i<n)add(i,i+1,inf,0); add(st,i+n,inf,p); if(i+m<=n)add(i,i+m+n,inf,f); if(i+nn<=n)add(i,i+nn+n,inf,s); } } ll min_cost; int dis[N],book[N],cnt; bool vis[N]; deque<int>q; int spfa() { memset(dis,inf,sizeof dis); dis[st]=0;q.push_back(st); int u,v; while(!q.empty()) { u=q.front();q.pop_front();vis[u]=0; for(register int i=head[u];i;i=e[i].nex) { v=e[i].v; if(e[i].flow&&cmin(dis[v],dis[u]+e[i].w)) { if(vis[v])continue; if(!q.empty()&&dis[v]<=dis[q.front()])q.push_front(v); else q.push_back(v); vis[v]=1; } } } return dis[ed]^inf; } int dfs(int u,int flow) { book[u]=cnt; if(u==ed)return flow; int sum=0,v,f; for(register int &i=cur[u];i&&flow;i=e[i].nex) { v=e[i].v; if(book[v]^cnt&&e[i].flow&&dis[u]+e[i].w==dis[v]) { f=dfs(v,min(flow,e[i].flow)); e[i].flow-=f;e[i^1].flow+=f; flow-=f;sum+=f; min_cost+=1ll*e[i].w*f; } } return sum; } void work() { while(spfa()) { ++cnt; memcpy(cur,head,sizeof cur); dfs(st,inf); } printf("%lld\n",min_cost); } int main() { file(); input(); work(); return 0; }