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 }
View Code

 

 

1221: [HNOI2001] 软件开发

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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

4 1 2 3 2 1
8 2 1 6

Sample Output

38

HINT

Source

posted @ 2016-05-27 23:21  晴歌。  阅读(251)  评论(0编辑  收藏  举报