【费用流】BZOJ1221-[HNOI2001] 软件开发
【题目大意】
某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员每天提供一块消毒毛巾,这种消毒毛巾使用一天后必须再做消毒处理后才能使用。消毒方式有两种,A种方式的消毒需要a天时间,B种方式的消毒需要b天(b>a),A种消毒方式的费用为每块毛巾fA, B种消毒方式的费用为每块毛巾fB,而买一块新毛巾的费用为f(新毛巾是已消毒的,当天可以使用);而且f>fA>fB。公司经理正在规划在这n天中,每天买多少块新毛巾、每天送多少块毛巾进行A种消毒和每天送多少块毛巾进行B种消毒。当然,公司经理希望费用最低。你的任务就是:为该软件公司计划每天买多少块毛巾、每天多少块毛巾进行A种消毒和多少毛巾进行B种消毒,使公司在这项n天的软件开发中,提供毛巾服务的总费用最低。
【思路】
将每一天拆为两个点,左边表示将要去消毒的毛巾,右边表示消毒好的毛巾,进行建图。
设置一个源点S和汇点T
·由源点向每天连一条容量为towel[i],费用为0的边;由每天向汇点连一条容量为towel[i],费用为0的边。
由于每条毛巾可以用AB方法进行消毒
·由i向(i+n)+ta+1连一条容量为INF,费用为fa的边;由i向(i+n)+tb+1连一条容量为INF,费用为fb的边
由于当天未用完的毛巾可以直接留下给下一天
·由源点向i+n连一条容量为INF,费用为f的边
由于当天的毛巾可以留到第二天再进行清洗
·由i向i+1连一条容量为INF,费用为0的边
因为中间边的容量均为INF,可以保证最大流是满流,这种情况下的最小费用流答案即为最小花费。
【错误点】
犯了点零零星星的小错,依然是初始化错误+手残打错,已经写进了注释。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 #define S 0 8 #define T 2*n+1 9 using namespace std; 10 const int MAXN=2000+100; 11 const int INF=0x7fffffff; 12 struct node 13 { 14 int to,pos,cap,cost; 15 }; 16 17 vector<node> E[MAXN]; 18 int n,ta,tb,f,fa,fb; 19 int towel[MAXN]; 20 int pre[MAXN],preedge[MAXN]; 21 22 void addedge(int u,int v,int w,int c) 23 { 24 E[u].push_back((node){v,E[v].size(),w,c}); 25 E[v].push_back((node){u,E[u].size()-1,0,-c}); 26 } 27 28 void init() 29 { 30 scanf("%d%d%d%d%d%d",&n,&ta,&tb,&f,&fa,&fb); 31 for (int i=1;i<=n;i++) 32 { 33 scanf("%d",&towel[i]); 34 35 /*将一天拆为两个点, 36 由源点向每天连一条容量为towel[i],费用为0的边 37 由每天向汇点连一条容量为towel[i],费用为0的边*/ 38 addedge(S,i,towel[i],0); 39 addedge(i+n,T,towel[i],0); 40 41 /*由于每条毛巾可以用AB方法进行消毒 42 由i向(i+n)+ta+1连一条容量为INF,费用为fa的边 43 由i向(i+n)+tb+1连一条容量为INF,费用为fb的边*/ 44 if (i+n+ta+1<=2*n) addedge(i,i+n+ta+1,INF,fa); 45 if (i+n+tb+1<=2*n) addedge(i,i+n+tb+1,INF,fb); 46 47 /*由于当天未用完的毛巾可以直接留下给下一天 48 或者当天的毛巾可以留到第二天再进行清洗 49 由源点向i+n连一条容量为INF,费用为f的边 50 由i向i+1连一条容量为INF,费用为0的边*/ 51 addedge(S,i+n,INF,f); 52 if (i+1<=n) addedge(i,i+1,INF,0); 53 } 54 } 55 56 int SPFA() 57 { 58 int vis[MAXN],dis[MAXN]; 59 queue<int> que; 60 memset(vis,0,sizeof(vis)); 61 memset(pre,-1,sizeof(pre)); 62 for (int i=1;i<=T;i++) dis[i]=INF; //这里一开始草率地初始化为127,事实上这个值和INF不相等,会导致判断出错 63 vis[S]=1; 64 dis[S]=0; 65 que.push(S); 66 while (!que.empty()) 67 { 68 int head=que.front();que.pop(); 69 vis[head]=0; 70 for (int i=0;i<E[head].size();i++) //这里打成了E[i].size()查了半天才发现orz 71 { 72 node &tmp=E[head][i]; 73 if (tmp.cap>0 && dis[tmp.to]>dis[head]+tmp.cost) 74 { 75 dis[tmp.to]=dis[head]+tmp.cost; 76 pre[tmp.to]=head; 77 preedge[tmp.to]=i; 78 if (!vis[tmp.to]) 79 { 80 vis[tmp.to]=1; 81 que.push(tmp.to); 82 } 83 } 84 } 85 } 86 if (dis[T]==INF) return 0;else return 1; 87 } 88 89 void mcmf() 90 { 91 int ans=0; 92 while (SPFA()) 93 { 94 int flow=INF; 95 for (int i=T;pre[i]!=-1;i=pre[i]) 96 { 97 flow=min(flow,E[pre[i]][preedge[i]].cap); 98 } 99 for (int i=T;pre[i]!=-1;i=pre[i]) 100 { 101 node &tmp=E[pre[i]][preedge[i]]; 102 ans+=flow*tmp.cost; 103 tmp.cap-=flow; 104 E[tmp.to][tmp.pos].cap+=flow; 105 } 106 } 107 cout<<ans<<endl; 108 } 109 110 int main() 111 { 112 init(); 113 mcmf(); 114 return 0; 115 }