BZOJ_1221_ [HNOI2001]_软件开发(最小费用流,网络流24题#10)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1221
n天,每天需要r个毛巾,用完以后可以洗,要么花fa洗a天,要么花fb洗b天,毛巾不够了可以话f买一个,问最少需要多少钱.
分析
把每天拆成两个点:x[i]表示第i天的脏毛巾,y[i]表示第i天要用的毛巾.
1.s向x[i]连弧,容量为r[i],花费为0,表示每天会用脏r[i]条毛巾.
2.x[i]向x[i+1]连弧(注意边界),容量为INF,花费为0,表示把第i天的脏毛巾搁置到第i+1天(由于可能连续搁置多日,所以可能不只r[i]个).
3.x[i]向y[i+a+1]连弧(注意边界),容量为INF,花费为fa,表示把第i天的脏毛巾拿去进行a洗.
4.x[i]向x[i+b+1]连弧(注意边界),容量为INF,花费为fb,同上.
5.s向y[i]连弧,容量为INF(其实可以是r[i],因为y只流向t,最多流r[i]),花费为f,表示新买毛巾.
6.y[i]向t连弧,容量为r[i],花费为0,表示第i天用了r[i]个毛巾.
注意:
1.用^运算的时候(0,1)是一组,(2,3)是一组这样子,所以从偶数开始,又不能从0开始,所以从2开始.(debug了好久...)
p.s.
1.第一次手写队列,没问题,没想到是手写的链表错了..........
2.网络流24题?以后每天做一道试试吧.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=1000+5,INF=1<<27; 5 int cnt=1; 6 int head[maxn<<1],q[maxn<<1],d[maxn<<1],p[maxn<<1]; 7 bool vis[maxn<<1]; 8 9 struct edge{ 10 int from,to,cap,cost,next; 11 edge(){} 12 edge(int from,int to,int cap,int cost,int next):from(from),to(to),cap(cap),cost(cost),next(next){} 13 }g[maxn*maxn]; 14 void add_edge(int u,int v,int cap,int cost){ 15 g[++cnt]=edge(u,v,cap,cost,head[u]); head[u]=cnt; 16 g[++cnt]=edge(v,u,0,-cost,head[v]); head[v]=cnt; 17 } 18 bool spfa(int s,int t){ 19 for(int i=s;i<=t;i++) d[i]=INF, vis[i]=false; 20 d[s]=0; vis[s]=true; 21 int front=0,tail=0; 22 q[tail++]=s; 23 while(front!=tail){ 24 int u=q[front++]; if(front==2001) front=0; 25 vis[u]=false; 26 for(int i=head[u];i;i=g[i].next) if(g[i].cap&&d[g[i].to]>d[u]+g[i].cost){ 27 d[g[i].to]=d[u]+g[i].cost; 28 p[g[i].to]=i; 29 if(!vis[g[i].to]){ 30 vis[g[i].to]=true; 31 q[tail++]=g[i].to; if(tail==2001) tail=0; 32 } 33 } 34 } 35 return d[t]!=INF; 36 } 37 int min_cost(int s,int t){ 38 int ret=0,f; 39 while(spfa(s,t)){ 40 f=INF; 41 for(int u=t;u!=s;u=g[p[u]].from) f=min(f,g[p[u]].cap); 42 for(int u=t;u!=s;u=g[p[u]].from) g[p[u]].cap-=f, g[p[u]^1].cap+=f; 43 ret+=d[t]*f; 44 } 45 return ret; 46 } 47 int main(){ 48 int n,a,b,f,fa,fb; 49 scanf("%d%d%d%d%d%d",&n,&a,&b,&f,&fa,&fb); 50 int s=0,t=(n<<1)+1; 51 for(int i=1;i<=n;i++){ 52 if(i+1<=n) add_edge(i,i+1,INF,0); 53 if(i+a+1<=n) add_edge(i,n+i+a+1,INF,fa); 54 if(i+b+1<=n) add_edge(i,n+i+b+1,INF,fb); 55 add_edge(0,n+i,INF,f); 56 } 57 for(int i=1;i<=n;i++){ 58 int r; scanf("%d",&r); 59 add_edge(s,i,r,0); 60 add_edge(n+i,t,r,0); 61 } 62 printf("%d\n",min_cost(s,t)); 63 return 0; 64 }
1221: [HNOI2001] 软件开发
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1236 Solved: 685
[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
8 2 1 6