BZOJ网络流+费用流:【1221[HNOI2001] 软件开发】

来源:互联网 发布:网络推广的书籍 编辑:程序博客网 时间:2024/05/16 08:43

1221: [HNOI2001] 软件开发

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1352  Solved: 749
[Submit][Status][Discuss]

题解:
经典网络流24题中的餐巾计划问题:

这个问题的主要约束条件是每天的餐巾够用,而餐巾的来源可能是最新购买,也可能是前几天送洗,今天刚刚洗好的餐巾。每天用完的餐巾可以选择送到快洗部或慢洗部,或者留到下一天再处理。

经过分析可以把每天要用的和用完的分离开处理,建模后就是二分图。二分图X集合中顶点Xi表示第i天用完的餐巾,其数量为ri,所以从S向Xi连接容量为ri的边作为限制。Y集合中每个点Yi则是第i天需要的餐巾,数量为ri,与T连接的边容量作为限制。每天用完的餐巾可以选择留到下一天(Xi->Xi+1),不需要花费,送到快洗部(Xi->Yi+m+1)(+1天是因为从第二天开始清洗),费用为f;送到慢洗部(Xi->Yi+n+1),费用为s。每天需要的餐巾除了刚刚洗好的餐巾,还可能是新购买的(S->Yi),费用为p。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm> #include<queue>using namespace std;const int inf=1e9;const int N=2005;const int M=100005;int from[M],to[M],nxt[M],w[M],p[M],lj[N],cnt=1;void add(int f,int t,int ww,int pp){    cnt++,from[cnt]=f,to[cnt]=t,nxt[cnt]=lj[f],lj[f]=cnt,w[cnt]=ww,p[cnt]=pp;    cnt++,from[cnt]=t,to[cnt]=f,nxt[cnt]=lj[t],lj[t]=cnt,w[cnt]=0,p[cnt]=-pp;}int day,fp,ff,fs,f,s,ans,S,T;queue<int>Q;int d[N],bef[N];bool inq[N];bool spfa(){    for(int i=S;i<=T;i++) d[i]=inf;   d[S]=0;   Q.push(S);   while(!Q.empty())   {   int x=Q.front();   Q.pop();   inq[x]=false;   for(int i=lj[x];i;i=nxt[i])   if(w[i]&&d[to[i]]>d[x]+p[i])    {   d[to[i]]=d[x]+p[i];   bef[to[i]]=i;   if(!inq[to[i]])    {   Q.push(to[i]);   inq[to[i]]=true;   }    }}    if(d[T]==inf) return false;return true;}void fyl(){while(spfa())    {int x=T,flow=inf;    while(x!=S)    {        flow=min(flow,w[bef[x]]);        x=from[bef[x]];    }    x=T;    ans+=d[T]*flow;    while(x!=S)    {        w[bef[x]]-=flow;        w[(bef[x]^1)]+=flow;        x=from[bef[x]];    }    }}int main(){    scanf("%d%d%d%d%d%d",&day,&f,&s,&fp,&ff,&fs);   S=0,T=day*2+1;    for(int i=1;i<=day;i++)    {        if(i+1<=day) add(i,i+1,inf,0);        if(i+f+1<=day) add(i,day+i+f+1,inf,ff);        if(i+s+1<=day) add(i,day+i+s+1,inf,fs);        add(S,day+i,inf,fp);    }    for(int i=1;i<=day;i++)    {    int x;        scanf("%d",&x);        add(S,i,x,0);        add(day+i,T,x,0);    }    while(spfa()) fyl();    printf("%d",ans);}

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

[Submit][Status][Discuss]


题解:
经典网络流24题中的餐巾计划问题:(hzwer的题解:)

这个问题的主要约束条件是每天的餐巾够用,而餐巾的来源可能是最新购买,也可能是前几天送洗,今天刚刚洗好的餐巾。每天用完的餐巾可以选择送到快洗部或慢洗部,或者留到下一天再处理。

经过分析可以把每天要用的和用完的分离开处理,建模后就是二分图。二分图X集合中顶点Xi表示第i天用完的餐巾,其数量为ri,所以从S向Xi连接容量为ri的边作为限制。Y集合中每个点Yi则是第i天需要的餐巾,数量为ri,与T连接的边容量作为限制。每天用完的餐巾可以选择留到下一天(Xi->Xi+1),不需要花费,送到快洗部(Xi->Yi+m+1)(+1天是因为从第二天开始清洗),费用为f;送到慢洗部(Xi->Yi+n+1),费用为s。每天需要的餐巾除了刚刚洗好的餐巾,还可能是新购买的(S->Yi),费用为p。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm> #include<queue>using namespace std;const int inf=1e9;const int N=2005;const int M=100005;int from[M],to[M],nxt[M],w[M],p[M],lj[N],cnt=1;void add(int f,int t,int ww,int pp){    cnt++,from[cnt]=f,to[cnt]=t,nxt[cnt]=lj[f],lj[f]=cnt,w[cnt]=ww,p[cnt]=pp;    cnt++,from[cnt]=t,to[cnt]=f,nxt[cnt]=lj[t],lj[t]=cnt,w[cnt]=0,p[cnt]=-pp;}int day,fp,ff,fs,f,s,ans,S,T;queue<int>Q;int d[N],bef[N];bool inq[N];bool spfa(){    for(int i=S;i<=T;i++) d[i]=inf;   d[S]=0;   Q.push(S);   while(!Q.empty())   {   int x=Q.front();   Q.pop();   inq[x]=false;   for(int i=lj[x];i;i=nxt[i])   if(w[i]&&d[to[i]]>d[x]+p[i])    {   d[to[i]]=d[x]+p[i];   bef[to[i]]=i;   if(!inq[to[i]])    {   Q.push(to[i]);   inq[to[i]]=true;   }    }}    if(d[T]==inf) return false;return true;}void fyl(){while(spfa())    {int x=T,flow=inf;    while(x!=S)    {        flow=min(flow,w[bef[x]]);        x=from[bef[x]];    }    x=T;    ans+=d[T]*flow;    while(x!=S)    {        w[bef[x]]-=flow;        w[(bef[x]^1)]+=flow;        x=from[bef[x]];    }    }}int main(){    scanf("%d%d%d%d%d%d",&day,&f,&s,&fp,&ff,&fs);   S=0,T=day*2+1;    for(int i=1;i<=day;i++)    {        if(i+1<=day) add(i,i+1,inf,0);        if(i+f+1<=day) add(i,day+i+f+1,inf,ff);        if(i+s+1<=day) add(i,day+i+s+1,inf,fs);        add(S,day+i,inf,fp);    }    for(int i=1;i<=day;i++)    {    int x;        scanf("%d",&x);        add(S,i,x,0);        add(day+i,T,x,0);    }    while(spfa()) fyl();    printf("%d",ans);}
0 0
原创粉丝点击