最小费用最大流 洛谷 1251
题意:
这是一道最小费用(费用指单价)最大流的题目。
首先,我们拆点,将一天拆成晚上和早上,每天晚上会受到脏餐巾(来源:当天早上用完的餐巾,在这道题中可理解为从原点获得),每天早上又有干净的餐巾(来源:购买、快洗店、慢洗店)。
1.从原点向每一天晚上连一条流量为当天所用餐巾x,费用为0的边,表示每天晚上从起点获得x条脏餐巾。
2.从每一天早上向汇点连一条流量为当天所用餐巾x,费用为0的边,每天白天,表示向汇点提供x条干净的餐巾,流满时表示第i天的餐巾够用 。 3.从每一天晚上向第二天晚上连一条流量为INF,费用为0的边,表示每天晚上可以将脏餐巾留到第二天晚上(注意不是早上,因为脏餐巾在早上不可以使用)。
4.从每一天晚上向这一天+快洗所用天数t1的那一天早上连一条流量为INF,费用为快洗所用钱数的边,表示每天晚上可以送去快洗部,在地i+t1天早上收到餐巾 。
5.同理,从每一天晚上向这一天+慢洗所用天数t2的那一天早上连一条流量为INF,费用为慢洗所用钱数的边,表示每天晚上可以送去慢洗部,在地i+t2天早上收到餐巾 。
6.从起点向每一天早上连一条流量为INF,费用为购买餐巾所用钱数的边,表示每天早上可以购买餐巾 。 注意,以上6点需要建反向边!3~6点需要做判断(即连向的边必须<=n)
1 #include<cstdio> 2 #include<queue> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 #define INF 2147483647 7 #define LL long long 8 using namespace std; 9 const int maxn=1e5+10; 10 queue<int>q; 11 int n,m,m1,t1,m2,t2,num=-1,st,ed; 12 struct node{ 13 int u,v,w,cost,next; 14 }G[maxn]; 15 int b[maxn],head[maxn],pre[maxn],pos[maxn],max_flow[maxn]; 16 LL dis[maxn]; 17 bool vis[maxn]; 18 void build(int u,int v,int w,int cost) 19 { 20 G[++num].u=u;G[num].v=v;G[num].w=w;G[num].cost=cost;G[num].next=head[u];head[u]=num; 21 G[++num].u=v;G[num].v=u;G[num].w=0;G[num].cost=-cost;G[num].next=head[v];head[v]=num; 22 } 23 bool spfa() 24 { 25 memset(vis,true,sizeof(vis)); 26 vis[st]=false; 27 memset(dis,63,sizeof(dis)); 28 dis[st]=0; 29 max_flow[st]=INF; 30 q.push(st); 31 while(!q.empty()){ 32 int u=q.front(); 33 vis[u]=true; 34 q.pop(); 35 for(int i=head[u];i!=-1;i=G[i].next){ 36 int v=G[i].v; 37 if(G[i].w>0&&dis[v]>dis[u]+G[i].cost){ 38 dis[v]=dis[u]+G[i].cost; 39 pos[v]=u; 40 pre[v]=i; 41 max_flow[v]=min(max_flow[u],G[i].w); 42 if(vis[v]){ 43 q.push(v); 44 vis[v]=false; 45 } 46 } 47 } 48 } 49 return dis[ed]<4557430888798830399; 50 } 51 LL flow() 52 { 53 LL ans=0; 54 while(spfa()){ 55 ans+=max_flow[ed]*dis[ed]; 56 for(int i=ed;i!=st;i=pos[i]){ 57 G[pre[i]].w-=max_flow[ed]; 58 G[pre[i]^1].w+=max_flow[ed]; 59 } 60 } 61 return ans; 62 } 63 int main() 64 { 65 int x; 66 scanf("%d",&n); 67 st=0,ed=2*n+1; 68 memset(head,-1,sizeof(head)); 69 for(int i=1;i<=n;i++){ 70 scanf("%d",&x); 71 build(st,i,x,0);//每天晚上从起点获得x条脏餐巾 72 build(i+n,ed,x,0);//每天白天,向汇点提供x条干净的餐巾,流满时表示第i天的餐巾够用 73 } 74 scanf("%d %d %d %d %d",&m,&t1,&m1,&t2,&m2); 75 for(int i=1;i<=n;i++){ 76 if(i+1<=n) build(i,i+1,INF,0);//每天晚上可以将脏餐巾留到第二天晚上 77 if(i+t1<=n) build(i,i+n+t1,INF,m1);//每天晚上可以送去快洗部,在地i+t1天早上收到餐巾 78 if(i+t2<=n) build(i,i+n+t2,INF,m2);//每天晚上可以送去慢洗部,在地i+t2天早上收到餐巾 79 build(st,i+n,INF,m);//每天早上可以购买餐巾 80 } 81 printf("%lld",flow()); 82 }