https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2660
大白书p371
题意: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;
}
// UVa11613 Acme Corporation
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<cassert>
using namespace std;
const int maxn = 202 + 10;
const int INF = 1000000000;
typedef long long LL;
struct Edge {
int from, to, cap, flow, cost;
};
struct MCMF {
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn]; // 是否在队列中
int d[maxn]; // Bellman-Ford
int p[maxn]; // 上一条弧
int a[maxn]; // 可改进量
void init(int n) {
this->n = n;
for(int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap, int 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(int s, int t, LL& ans) {
for(int i = 0; i < n; i++) d[i] = INF;
memset(inq, 0, sizeof(inq));
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;
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;
ans += (LL)d[t] * (LL)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 cost = 0;
while(BellmanFord(s, t, cost));
return cost;
}
};
MCMF g;
int main() {
int T, month, store_cost;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++) {
scanf("%d%d", &month, &store_cost);
g.init(2*month+2);
int source = 0, sink = 2*month+1;
for(int i = 1; i <= month; i++) {
int make_cost, make_limit, price, sell_limit, max_store;
scanf("%d%d%d%d%d", &make_cost, &make_limit, &price, &sell_limit, &max_store);
g.AddEdge(source, i, make_limit, make_cost);
g.AddEdge(month+i, sink, sell_limit, -price); // 收益是负费用
for(int j = 0; j <= max_store; j++) if(i + j <= month)
g.AddEdge(i, month+i+j, INF, store_cost * j); // 存j个月以后卖
}
printf("Case %d: %lld\n", kase, -g.Mincost(source, sink));
}
return 0;
}