bzoj 1221(费用流)

1221: [HNOI2001] 软件开发

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 1209  Solved: 671

[Submit][Status][Discuss]

Description

某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。

Input

第1行为n,a,b,f,fA,fB. 第2行为n1,n2,……,nn. (注:1≤f,fA,fB≤60,1≤n≤1000)

Output

最少费用

Sample Input

4 1 2 3 2 1

8 2 1 6

Sample Output

38

解题思路:经典的费用流。对于费用流的问题,见图如果遇到

像最后要汇到汇点的流要留到下个点时,可以拆成两个点,

然后将新开的点作为之前要流出去的点。

#include<cstdio>

#include<cstring>

#include<iostream>

#include<algorithm>

using namespace std;

int n,a,bg,fg,fa,fb,len,S,T,ans;

int to[21000],from[20000],next[20000],h[20000],f[20000],w[20000];

int dis[2101],q[1000000],pre[2101];

const int INF=0x7fffffff;

bool b[2101];

inline int read()

{

char y; int x=0,f=1; y=getchar();

while (y<‘0‘ || y>‘9‘) {if (y==‘-‘) f=-1; y=getchar();}

while (y>=‘0‘&& y<=‘9‘) {x=x*10+int(y)-48; y=getchar();}

return x*f;

}

void insert(int x,int y,int flow,int v)

{

++len; to[len]=y; from[len]=x; next[len]=h[x]; h[x]=len; f[len]=flow; w[len]=v;

}

bool spfa()

{

memset(dis,0x7f,sizeof(dis)); dis[S]=0;

memset(b,true,sizeof(b)); b[S]=false;

int tail=1,head=0; ++tail; q[tail]=S;

while (head<tail)

{

++head;

int u=h[q[head]];

while (u!=0)

{

if (f[u]>0 && dis[to[u]]>dis[q[head]]+w[u])

{

dis[to[u]]=dis[q[head]]+w[u];

pre[to[u]]=u;

if (b[to[u]])

{

b[to[u]]=false;

++tail; q[tail]=to[u];

}

}

u=next[u];

}

b[q[head]]=true;

}

if (dis[T]<100000000) return true;else return false;

}

void mcf()

{

int now=T; int mx=0x7fffffff;

while (now!=S)

{

mx=min(mx,f[pre[now]]);

now=from[pre[now]];

}

now=T;

while (now!=S)

{

ans+=w[pre[now]]*mx;

f[pre[now]]-=mx; f[pre[now]^1]+=mx;

now=from[pre[now]];

}

}

int main()

{

n=read(); a=read(); bg=read(); fg=read(); fa=read(); fb=read();

S=0; T=2001; len=1;

for (int i=1;i<=n;++i)

{

int x=read();

insert(S,i,x,0); insert(i,S,0,0);

insert(i+n,T,x,0); insert(T,i+n,0,0);

insert(S,i+n,INF,fg); insert(i+n,S,0,-fg);

if (i!=n) {insert(i+n,i+n+1,INF,0); insert(i+n+1,i+n,0,0);}

if (i+a+1<=n) insert(i,i+a+1+n,INF,fa),insert(i+a+1+n,i,0,-fa);

if (i+bg+1<=n) insert(i,i+bg+1+n,INF,fb),insert(i+bg+1+n,i,0,-fb);

}

ans=0;

while (spfa())

{

mcf();

}

printf("%d",ans);

}

时间: 2024-10-08 18:17:33

bzoj 1221(费用流)的相关文章

bzoj 3171(费用流)

3171: [Tjoi2013]循环格 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 785  Solved: 493 [Submit][Status][Discuss] Description 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c) ,你可以沿着箭头防线在格子间行走.即如果(r,c)是一个左箭头,那么走到(r,c-1);如果是右箭头那

bzoj 2245(费用流)

2245: [SDOI2011]工作安排 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1442  Solved: 689 [Submit][Status][Discuss] Description 你的公司接到了一批订单.订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件.公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别.一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另

BZOJ 4514 费用流

思路: 懒得写了 http://blog.csdn.net/werkeytom_ftd/article/details/51277482 //By SiriusRen #include <queue> #include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long #defin

[BZOJ 1221] [HNOI2001] 软件开发 【费用流 || 三分】

题目链接:BZOJ - 1221 题目分析 算法一:最小费用最大流 首先这是一道经典的网络流问题.每天建立两个节点,一个 i 表示使用毛巾,一个 i' 表示这天用过的毛巾. 然后 i 向 T 连 Ai (第 i 天需要的毛巾数).从 S 向 i' 连 Ai ,这样这天新增的用过的毛巾就是 Ai 了. 然后 i' 可以连向 (i+1)' ,表示留到下一天再处理,i' 还可以流向 i+p+1 和 i+q+1,表示洗了之后再次使用,这两种边是有费用的. 还有就是新购买毛巾,从 S 向 i 连,费用就是

BZOJ 1221: [HNOI2001] 软件开发(最小费用最大流)

不知道为什么这么慢.... 费用流,拆点.... -------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i, n ) for( int

BZOJ 1221 HNOI 2001 软件开发/网络流24题 餐巾计划问题 最小费用最大流

题目大意:有一个软件公司,每天需要给一些员工准备消毒毛巾,这些毛巾可以循环利用,但是需要消毒.可以将毛巾送去消毒,有两种方式,A天fA花费,B天fB花费.或者还可以直接买新毛巾,问为了满足员工的需求,至少需要花多少钱. 思路:经典的费用流问题.将每一天拆点,S向每一天<<1连边,约束每一天需要多少毛巾:每一天<<1|1向T连边,约束每一天需要的毛巾.每一天<<1向这一天清洗的毛巾能够使用的那一天<<1|1,注意A和B.毛巾可以延后使用,那么每一天<&l

BZOJ 2668 交换棋子(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与m[i,j]次交换. 思路: 我们将1看做要移动的数字,将0看做空白.那么若1在始末状态个数不同则无解:如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0.将每个格子拆为为个点p0,p1,p2: (1)若格子初始为1,则连边:<s,p0,1,0>

BZOJ 3171 循环格(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3171 题意: 思路:若能构成循环,则每个格子的入度出度 均为1.因此将每个点拆成两个点x1,x2,分别作为出点和入点.出点向周围四个点的入点连边,流1,费用视该格子的字母而定.该格子的字母正好是这个方 向则费用为0否则为1.原点S向每个出点连边,流量1费用0:每个入点向汇点连边,流量1费用0.求最小费用最大流即可. struct node { int u,v,next,cost,cap

BZOJ 2661 连连看(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2661 题意:给出一个区间[a,b]中的全部整数,如果其中某两个数x,y(设x>y)的平方差x^2-y^2是一个完全平方数z^2,并且y与z互质,那么就可以将x和y一起消除,同时得到x+y点分数.要求就是,消除的数对尽可能多的前提下,得到的分数尽量多. 思路:首先暴力出所有合法的数对(x,y).然后将每个用到的数字拆成两个点,每个数对连一条边.最后的答案除以2即可. struct nod