题意:Acme公司生产一种X元素。给出该元素在未来M个月中每个月的单位售价,最大产量,生产成本,最大销售量,以及最大存储时间,计算公司能获得的最大利润。
思路:费用流。可以将每个月拆成两个点,分别看成月生产和月销售。建立源点S和汇点T。从S向每个月生产点连一条容量为ni,费用为mi的弧,在从每个月销售点向T连一条容量为si,费用为-pi的弧。然后从每个月生产点向存储时间内的月销售点连一条容量为inf,费用为存储时间×I的弧。最后做费用流,当增广到最短路径大于0时停止增广即可。
代码:
#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 2139062143
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
//#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=200+100;
struct Edge
{
ll from,to,cap,flow,cost;
};
struct MCFC
{
vector<Edge>edges;
vector<int>G[maxn];
int m,n,s,t;
ll d[maxn],inq[maxn],p[maxn],a[maxn];
void Init(int n)
{
this->n=n;
for(int i=0;i<=n;++i) G[i].clear();
edges.clear();
}
void AddEdges(ll from,ll to,ll cap,ll cost)
{
edges.push_back((Edge){from,to,cap,0,cost});
edges.push_back((Edge){to,from,0,0,-cost});
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(ll s,ll t,ll & flow,ll & cost)
{
memset(inq,0,sizeof(inq));
for(int i=0;i<=n;++i) d[i]=Inf;
d[s]=0;p[s]=0;inq[s]=1;a[s]=Inf;
queue<int>q;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
inq[u]=0;
for(int i=0;i<G[u].size();++i)
{
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+=a[t];
cost+=d[t]*a[t];
int u=t;
while(u!=s)
{
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
u=edges[p[u]].from;
}
return true;
}
ll Mincost(int s,int t)
{
ll flow=0,cost=0;
while(BellmanFord(s,t,flow,cost));
return cost;
}
}mcfc;
struct MonInfo
{
int mi,ni,pi,si,E;
};
MonInfo mon[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t,tcase=0;
scanf("%d",&t);
while(t--)
{
tcase++;
int M,I;
scanf("%d%d",&M,&I);
int N=2*M+1;
mcfc.Init(N);
for(int i=1;i<=M;++i)
scanf("%d%d%d%d%d",&mon[i].mi,&mon[i].ni,&mon[i].pi,&mon[i].si,&mon[i].E);
for(int i=1;i<=M;++i)
{
mcfc.AddEdges(0,i,mon[i].ni,mon[i].mi);
int z=min(M,mon[i].E+i);
for(int j=i;j<=z;++j)
{
mcfc.AddEdges(i,M+j,Inf,(j-i)*I);
}
}
for(int i=1;i<=M;++i)
mcfc.AddEdges(i+M,N,mon[i].si,-mon[i].pi);
ll ans=mcfc.Mincost(0,N);
printf("Case %d: %lld\n",tcase,-ans);
}
return 0;
}