UVA-11613 Acme Corporation (最大费用最大流+拆点)
题目大意:有一种商品X,其每每单位存放一个月的代价I固定。并且已知其每月的最大生产量、生产每单位的的代价、最大销售量和销售单价,还已知每个月生产的X能最多能存放的时间(以月为单位)。问只考虑前m个月,最多能获得多少利润。
题目分析:增加源点s和汇点t,将每一个月视作一个节点。建立图模型如下:将每一个节点拆成两个,即将v拆成v和v1,从s向所有的v连一条弧,容量为该月最大生产量,费用为该月的单位生产代价;然后从所有的v1出发连一条弧向t,容量为该月最大销售量,费用为销售单价的相反数;最后,从v出发向所有它能存放到的月数u对应的u1连一条弧,容量为正无穷大,费用为I*(u-v)。对该模型求最小费用最大流,显然,这里对最小费用取相反数便的最大利润。
代码如下:
# include<iostream> # include<cstdio> # include<cmath> # include<string> # include<vector> # include<list> # include<set> # include<map> # include<queue> # include<cstring> # include<algorithm> using namespace std; # define LL long long # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)) # define CLL(a,b,n) fill(a,a+n,b) const double inf=1e30; const int INF=1<<30; const int N=300; struct Edge { int fr,to; LL cap,flow,cost; Edge(int _fr,int _to,LL _cap,LL _flow,LL _cost):fr(_fr),to(_to),cap(_cap),flow(_flow),cost(_cost){} }; vector<Edge>edges; vector<int>G[N]; int p[N],inq[N],n,I; LL a[N],d[N]; void init() { edges.clear(); REP(i,0,n) G[i].clear(); } void addEdge(int fr,int to,LL cap,LL cost) { edges.push_back(Edge(fr,to,cap,0,cost)); edges.push_back(Edge(to,fr,0,0,-cost)); int m=edges.size(); G[fr].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s,int t,LL &flow,LL &cost) { CL(inq,0); CLL(d,INF,n); d[s]=0,inq[s]=1,p[s]=0,a[s]=INF; queue<int>q; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); inq[u]=0; REP(i,0,G[u].size()){ Edge &e=edges[G[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){ d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]){ q.push(e.to); inq[e.to]=1; } } } } if(d[t]>0) return false; flow+=(LL)a[t]; cost+=(LL)d[t]*(LL)a[t]; for(int u=t;u!=s;u=edges[p[u]].fr){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } return true; } LL Mincost(int s,int t) { LL flow=0,cost=0; while(BellmanFord(s,t,flow,cost)); return cost; } struct X { int m,n,p,s,E; }; X x[105]; int main() { int T,m,s,t,cas=0; scanf("%d",&T); while(T--) { scanf("%d%d",&m,&I); n=2*m+2; s=0,t=2*m+1; init(); REP(i,1,m+1) scanf("%d%d%d%d%d",&x[i].m,&x[i].n,&x[i].p,&x[i].s,&x[i].E); REP(i,1,m+1){ addEdge(0,2*i-1,x[i].n,x[i].m); addEdge(2*i,t,x[i].s,-x[i].p); } REP(i,1,m+1) REP(j,i,min(i+x[i].E,m)+1) addEdge(2*i-1,2*j,INF,I*(j-i)); printf("Case %d: %lld\n",++cas,-Mincost(s,t)); } return 0; }