题意好长。。。。变量好多。。。。
增加源点跟汇点。然后将每个月份看成一个点,然后拆成两个点u 跟 u+n。
从s向每个u连一条<n[u], m[i]>的弧,表示最多生产量及价值。
从每个u+n向t连一条<s[i], -p[i]>的弧,表示最多销量及价值。
对于存放的情况 for(int j=0; j<=e[u] ; j++) if(u + j <= M) ,由u向u+j+M连一条<INF, I*j>的弧,表示存放所要花费的价值。
这题并不需要满足销量最大,也就是不固定流量的最小费用流,也就是说当s-t增广长度大于0的时候停止增广就行了。还有,稠密图ZKW效率不是太高。。。。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> #define REP(i, n) for(int i=0; i<n; i++) #define CLR(a, b) memset(a, b, sizeof(a)) #define FF(i, a, b) for(int i=a; i<b; i++) #define LL long long using namespace std; const int maxn = 300; const int maxe = maxn*maxn/2; const int INF = 1e9; struct ZKW_flow { int st, ed, ecnt, n; int head[maxn], dis[maxn]; int cap[maxe], cost[maxe], to[maxe], next[maxe]; void init() { CLR(head, 0); ecnt = 2; } void AddEdge(int u, int v, int cc, int ww) { cap[ecnt] = cc; cost[ecnt] = ww; to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++; cap[ecnt] = 0; cost[ecnt] = -ww; to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++; } void spfa() { REP(i, n+1) dis[i] = INF; priority_queue<pair<int, int> > q; dis[st] = 0; q.push(make_pair(0, st)); while(!q.empty()) { int u = q.top().second, d = -q.top().first; q.pop(); if(dis[u] != d) continue; for(int p=head[u]; p; p=next[p]) { int& v = to[p]; if(cap[p] && dis[v] > d+cost[p]) { dis[v] = d + cost[p]; q.push(make_pair(-dis[v], v)); } } } REP(i, n+1) dis[i] = dis[ed] - dis[i]; } LL Mincost, Maxflow; bool use[maxn]; int add_flow(int u, int flow) { if(u == ed) { if(dis[st] > 0) return flow;//不固定流量的最小费用流 Maxflow += flow; Mincost += (LL)dis[st] * (LL)flow; return flow; } use[u] = true; int now = flow; for(int p=head[u]; p; p=next[p]) { int& v = to[p]; if(cap[p] && !use[v] && dis[u] == dis[v] + cost[p]) { int tmp = add_flow(v, min(now, cap[p])); cap[p] -= tmp; cap[p^1] += tmp; now -= tmp; if(!now) break; } } return flow - now; } bool modify_lable() { int d = INF; REP(u, n+1) if(use[u]) for(int p=head[u]; p; p=next[p]) { int& v = to[p]; if(cap[p] && !use[v]) d = min(d, dis[v] + cost[p] - dis[u]); } if(d == INF) return false; REP(i, n+1) if(use[i]) dis[i] += d; return true; } LL MCMF(int ss, int tt, int nn) { st = ss; ed = tt; n = nn; Mincost = Maxflow = 0; spfa(); while(true) { while(true) { CLR(use, 0); if(!add_flow(st, INF)) break; } if(!modify_lable()) break; } return Mincost; } }solver; int T, M, I, st, ed; int m[maxn], n[maxn], p[maxn], s[maxn], e[maxn]; int main() { scanf("%d", &T); FF(kase, 1, T+1) { scanf("%d%d", &M, &I); solver.init(); st = 0, ed = M * 2 + 1; FF(i, 1, M+1) scanf("%d%d%d%d%d", &m[i], &n[i], &p[i], &s[i], &e[i]); FF(i, 1, M+1) { solver.AddEdge(st, i, n[i], m[i]); solver.AddEdge(i+M, ed, s[i], -p[i]); REP(j, e[i]+1) if(i + j <= M) solver.AddEdge(i, i+j+M, n[i], I*j); else break; } printf("Case %d: %lld ", kase, -solver.MCMF(st, ed, ed)); } return 0; }