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;
}
posted @ 2015-04-21 19:58  NanoApe  阅读(188)  评论(0编辑  收藏  举报
AmazingCounters.com