BZOJ-1221 软件开发
这题是基于一道经典的费用流模型。
将每天拆成两个点i和j,新增源和汇并建立六种边:
1.从源出发到每个i点,flow为+∞,cost为每条新餐巾的价值,表示这一天所使用的餐巾中来自购买的餐巾
2.从源出发到每个j点,flow为每天所需的餐巾数,cost为0,表示这一天最多可使用的餐巾
3.从每个i点出发至汇,flow为每天所需的餐巾数,cost为0,表示这一天应该使用的餐巾
4.从每个j点出发至下一个j点,flow为+∞,cost为0,表示这一天使用后的餐巾移至下一天
5.从每个j点出发至下a个i点,flow为+∞,cost为第一种消毒的费用,表示这一天所使用的餐巾中来自第一种消毒后的餐巾
6.从每个j点出发至下b个i点,flow为+∞,cost为第二种消毒的费用,表示这一天所使用的餐巾中来自第二种消毒后的餐巾
然后最小费用最大流跑之。
基于图的稀疏,我用ZKW费用流实现。
#include <cstdlib> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <iostream> #include <deque> using namespace std; typedef long long ll; #define rep(i, l, r) for(int i=l; i<=r; i++) #define clr(x, c) memset(x, c, sizeof(c)) #define travel(x) for(edge *p=fir[x]; p; p=p->n) if (p->f) #define pb push_back #define pf push_front #define maxv 2009 #define maxm 30009 #define inf 0x7fffffff int read() { int x=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x; } struct edge{int y, f, c; edge *n, *pair;} e[maxm], *fir[maxv], *pt; inline void Init(){pt=e; clr(fir, 0);} inline void Add(int x, int y, int f, int c) {pt->y=y, pt->f=f, pt->c=c, pt->n=fir[x]; fir[x]=pt++;} inline void AddE(int x, int y, int f, int c) {Add(x, y, f, c); Add(y, x, 0, -c); fir[x]->pair=fir[y], fir[y]->pair=fir[x];} int S, T, V, d[maxv]; ll cost=0; int dist[maxv], st[maxv]; bool b[maxv]; deque <int> q; inline void spfa() { rep(i, 1, V) d[i]=inf, b[i]=0; q.clear(); q.pb(S), d[S]=0, b[S]=1; while (!q.empty()) { int x=q.front(), y; q.pop_front(); b[x]=0; travel(x) if (d[y=p->y] > d[x]+p->c) { d[y]=d[x]+p->c; if (!b[y]) b[y]=1, (!q.empty() && d[q.front()]>d[y]) ? q.pf(y) : q.pb(y); } } } void dfs(int now) { b[now]=1; int y; travel(now) if (d[now]+p->c==d[y=p->y] && !b[y]) dist[y]=dist[now]-p->c, dfs(y); } int aug(int now, int flow) { if (now==T) {cost+=flow*(dist[S]-dist[T]); return flow;} b[now]=1; int rec=0, y, ret; travel(now) if (!b[y=p->y]) { if (dist[now]==dist[y]+p->c) { ret=aug(y, min(flow-rec, p->f)); p->f-=ret, p->pair->f+=ret; if ((rec+=ret)==flow) return flow; } else st[y]=min(st[y], dist[y]+p->c-dist[now]); } return rec; } inline bool relabel() { int a=inf; rep(i, 1, V) if (!b[i]) a=min(a, st[i]); if (a==inf) return 0; rep(i, 1, V) if (b[i]) dist[i]+=a; return 1; } inline void costflow() { spfa(); clr(b, 0); clr(dist, 0); dfs(S); while(1) { rep(i, 1, V) st[i]=inf; while(1) { rep(i, 1, V) b[i]=0;//clr(b, 0); if (!aug(S, inf)) break; } if (!relabel()) break; } } int n; int main(){ Init(); n=read(); S=n*2+1; T=V=n*2+2; int a=read(), b=read(), f=read(), fa=read(), fb=read(); rep(i, 1, n-a) AddE(i*2, (i+a+1)*2-1, inf, fa); rep(i, 1, n-b) AddE(i*2, (i+b+1)*2-1, inf, fb); rep(i, 1, n) a=read(), AddE(S, i*2-1, inf, f), AddE(S, i*2, a, 0), AddE(i*2-1, T, a, 0); rep(i, 1, n-1) AddE(i*2, i*2+2, inf, 0); costflow(); printf("%lld\n", cost); return 0; }