P1251 餐巾计划问题 (费用流)

题目链接

 

方法:

重点在建图!!!将一天拆成晚上和早上;

1. 从源点向每一天晚上连一条流量为当天所用餐巾x,费用为0的边;

2. 每一天早上向汇点连一条流量为当天所用餐巾x,费用为0的边;

3. 从每一天晚上向第二天晚上连一条流量为INF,费用为0的边,表示每天晚上可以将脏餐巾留到第二天晚上;

4. 从每一天晚上向这一天+快洗所用天数t1的那一天早上连一条流量为INF,费用为快洗所用钱数的边,表示每天晚上可以送去快洗部,在地i+t1天早上收到餐巾 ;

5. 从每一天晚上向这一天+慢洗所用天数t2的那一天早上连一条流量为INF,费用为慢洗所用钱数的边,表示每天晚上可以送去慢洗部,在地i+t2天早上收到餐巾;

6. 从起点向每一天早上连一条流量为INF,费用为购买餐巾所用钱数的边,表示每天早上可以购买餐巾 。

 Code:

  1 #include <bits/stdc++.h>
  2 #define LL long long
  3 using namespace std;
  4 
  5 const int maxn=2000;
  6 const int INF=0x7fffffff;
  7 int N;
  8 int S,T;
  9 struct Edge{
 10     int next, from, to, remain,fi;
 11 }e[100000];
 12 int head[10000];
 13 int en;
 14 LL dis[10000];
 15 int preEdge[10000];
 16 queue<int> q;
 17 int inqueue[10000];
 18 LL res;
 19 int minflow[10000];
 20 
 21 void addEdge(int from, int to, int flow, int fi){
 22     e[en].next=head[from];
 23     e[en].from=from;
 24     e[en].to=to;
 25     e[en].remain=flow;
 26     e[en].fi=fi;
 27     head[from]=en;
 28     ++en;
 29 }
 30 
 31 void add(int from, int to, int flow, int fi){
 32     addEdge(from,to,flow,fi);
 33     addEdge(to,from,0,-fi);
 34 }
 35 
 36 void spfa(){
 37     memset(minflow,0,sizeof(minflow));
 38     memset(dis,127,sizeof(dis));
 39     memset(preEdge,-1,sizeof(preEdge));
 40     dis[S]=0;
 41     minflow[S]=INF;
 42     q.push(S);
 43     inqueue[S]=1;
 44     while(!q.empty()){
 45         int u=q.front();
 46         q.pop();
 47         inqueue[u]=0;
 48         for(int i=head[u];i!=-1;i=e[i].next){
 49             int v=e[i].to;
 50             int c=e[i].fi;
 51             if(e[i].remain>0 && dis[u]+c<dis[v]){
 52                 dis[v]=dis[u]+c;
 53                 preEdge[v]=i;
 54                 minflow[v]=min(minflow[u],e[i].remain);
 55                 if(!inqueue[v]){
 56                     q.push(v);
 57                     inqueue[v]=1;
 58                 }
 59             }
 60         }
 61     }
 62 }
 63 
 64 void EK(){
 65 
 66     while(true){
 67         spfa();
 68         if(preEdge[T]==-1) break;
 69         int v=T;
 70         while(true){
 71             int edge=preEdge[v];
 72             if(edge==-1) break;
 73             e[edge].remain-=minflow[T];
 74             e[edge^1].remain+=minflow[T];
 75             v=e[edge].from;
 76         }
 77         res+=dis[T]*minflow[T];
 78     }
 79 }
 80 
 81 int main(){
 82     memset(head,-1,sizeof(head));
 83     scanf("%d", &N);
 84     S=0;
 85     T=2*N+1;
 86     for(int i=1;i<=N;++i){
 87         int c;
 88         scanf("%d", &c);
 89         add(i,T,c,0);
 90         add(S,i+N,c,0);
 91     }
 92     int p, m, f, n, s;
 93     scanf("%d %d %d %d %d", &p, &m, &f, &n, &s);
 94     for(int i=1;i<=N;++i){
 95         add(S,i,INF,p);
 96         if(i+1<=N){
 97             add(i+N,i+1+N,INF,0);
 98         }
 99         if(i+m<=N){
100             add(i+N,i+m,INF,f);
101         }
102         if(i+n<=N){
103             add(i+N,i+n,INF,s);
104         }
105     }
106     EK();
107     printf("%lld",res);
108     return 0;
109 }
原文地址:https://www.cnblogs.com/FEIIEF/p/12244588.html