HDU 4780 Candy Factory(拆点费用流)

Problem Description
  A new candy factory opens in pku-town. The factory import M machines to produce high quality candies. These machines are numbered from 1 to M.
  There are N candies need to be produced. These candies are also numbered from 1 to N. For each candy i , it can be produced in any machine j. It also has a producing time(s i,t i) , meaning that candy i must start producing at time s i and will finish at t i. Otherwise if the start time is p i(s i < p i < t i) then candy will still finish at t i but need additional K*(p i - s i) cost. The candy can’t be produced if p i is greater than or equal to t i. Of course one machine can only produce at most one candy at a time and can’t stop once start producing.
  On the other hand, at time 0 all the machines are in their initial state and need to be “set up” or changed before starting producing. To set up Machine j from its initial state to the state which is suitable for producing candiy i, the time required is C ij and cost is D ij. To change a machine from the state suitable for candy i 1 into the state suitable for candy i 2, time required is E i1i2 and cost is F i1i2.
  As the manager of the factory you have to make a plan to produce all the N candies. While the sum of producing cost should be minimized.
 
Input
  There are multiple test cases.
  For each case, the first line contains three integers N(1<=N<=100), M(1<=M<=100), K(1<=K<=100) . The meaning is described above.
  Then N lines follow, each line contains 2 integers s i and t i(0 <= s i < t i <100000).
  Then N lines follow, each line contains M integers, the j-th integer of the i-th line indicating C ij(1<=C ij<=100000) .
  Then N lines follow, each line contains M integers, the j-th integer of the i-th line indicating D ij(1<=D ij<=100000) .
  Then N lines follow, each line contains N integers, the i 2-th integer of the i 1-th line indicating E i1i2(1<=E i1j2<=100000) . 
  Then N lines follow, each line contains N integers, the i 2-th integer of the i 1-th line indicating F i1i2(1 <= F i1j2<=100000) . 
  Since the same candy will only be produced once, E ii and F ii are meaningless and will always be -1.
  The input ends by N=0 M=0 K=0. Cases are separated with a blank line.
 
Output
For each test case, if all of M candies can be produced, output the sum of minimum producing cost in a single line. Otherwise output -1.
 
Sample Input
3 2 1 4 7 2 4 8 9 4 4 3 3 3 3 2 8 12 3 14 6 -1 1 1 1 -1 1 1 1 -1 -1 5 5 5 -1 5 5 5 -1 1 1 2 1 5 5 5 -1 -1 0 0 0
 
Sample Output
11 -1
Hint
For the first example, the answer can be achieved in the following way:
In the picture, S i represents setting up time for candy i, A i represents changing time for candy i and P i represents producing time for candy i . So the total cost includes: 
setting up machine 1 for candy 1, costs 2
setting up machine 2 for candy 2, costs 3
changing state from candy 2 to candy 3, costs 5
late start of candy 2, costs 1
题意
有N个糖果需要被生产,有M个机器,K代表额外花费系数
N行代表第i个糖果只能在[s[i],t[i]]的时间内被生产
接下来N*M代表生产第i个糖果的机器j在C[i][j]时间被开启
接下来N*M代表生产糖果i机器j的基础花费D[i][j],如果在第s[i]<p<t[i]的时间开始生产,也可以在t[i]生产出糖果,但需要额外花费(p-s[i])*K的花费
接下来N*N代表把机器J正在生产i糖果改成生产j糖果,所需的额外时间为E[i][j]
接下来N*N代表把机器J正在生产i糖果改成生产j糖果,所需的基础花费F[i][j],如果在第s[j]<p<t[j]的时间开始生产,也可以在t[j]生产出糖果,但需要额外花费(p-s[j])*K的花费
题解
一道比较复杂的费用流题,题意读了很久
为了保证糖果从源点S流出一次从汇点T流入一次,可以把N个糖果拆成左右糖,然后(S,左糖,1,0),然后(右糖,T,1,0)
然后考虑一个机器生产完i再去生产j的情况,如果时间允许,就连(左糖i,右糖j,1,基础花费F+额外花费)
然后新建一个点u,(S,u,m,0),(u,每个机器,1,0),如果机器i生产糖果j的时间C[j][i]<t[j]就连线(机器,右糖,1,基础花费D+额外花费)
代码
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int N=1e5+5;
  5 const int M=2e5+5;
  6 const int INF=0x3f3f3f3f;
  7 
  8 int FIR[N],FROM[M],TO[M],CAP[M],FLOW[M],COST[M],NEXT[M],tote;
  9 int pre[N],dist[N],q[400000];
 10 bool vis[N];
 11 int n,m,S,T;
 12 void init()
 13 {
 14     tote=0;
 15     memset(FIR,-1,sizeof(FIR));
 16 }
 17 void addEdge(int u,int v,int cap,int cost)
 18 {
 19     FROM[tote]=u;
 20     TO[tote]=v;
 21     CAP[tote]=cap;
 22     FLOW[tote]=0;
 23     COST[tote]=cost;
 24     NEXT[tote]=FIR[u];
 25     FIR[u]=tote++;
 26 
 27     FROM[tote]=v;
 28     TO[tote]=u;
 29     CAP[tote]=0;
 30     FLOW[tote]=0;
 31     COST[tote]=-cost;
 32     NEXT[tote]=FIR[v];
 33     FIR[v]=tote++;
 34 }
 35 bool SPFA(int s, int t)
 36 {
 37     memset(dist,INF,sizeof(dist));
 38     memset(vis,false,sizeof(vis));
 39     memset(pre,-1,sizeof(pre));
 40     dist[s] = 0;vis[s]=true;q[1]=s;
 41     int head=0,tail=1;
 42     while(head!=tail)
 43     {
 44         int u=q[++head];vis[u]=false;
 45         for(int v=FIR[u];v!=-1;v=NEXT[v])
 46         {
 47             if(dist[TO[v]]>dist[u]+COST[v]&&CAP[v]>FLOW[v])
 48             {
 49                 dist[TO[v]]=dist[u]+COST[v];
 50                 pre[TO[v]]=v;
 51                 if(!vis[TO[v]])
 52                 {
 53                     vis[TO[v]] = true;
 54                     q[++tail]=TO[v];
 55                 }
 56             }
 57         }
 58     }
 59     return pre[t]!=-1;
 60 }
 61 void MCMF(int s, int t, int &cost, int &flow)
 62 {
 63     flow=0;
 64     cost=0;
 65     while(SPFA(s,t))
 66     {
 67         int Min=INF;
 68         for(int v=pre[t];v!=-1;v=pre[TO[v^1]])
 69             Min=min(Min,CAP[v]-FLOW[v]);
 70         for(int v=pre[t];v!=-1;v=pre[TO[v^1]])
 71         {
 72             FLOW[v]+=Min;
 73             FLOW[v^1]-=Min;
 74             cost+=COST[v]*Min;
 75         }
 76         flow+=Min;
 77     }
 78 }
 79 int main()
 80 {
 81     int N,M,K,u,ss[105],tt[105],C[105][105],D[105][105],E[105][105],F[105][105];
 82     while(scanf("%d%d%d",&N,&M,&K)!=EOF,N||M||K)
 83     {
 84         init();
 85         for(int i=1;i<=N;i++)
 86             scanf("%d%d",&ss[i],&tt[i]);
 87         for(int i=1;i<=N;i++)for(int j=1;j<=M;j++)
 88             scanf("%d",&C[i][j]);
 89         for(int i=1;i<=N;i++)for(int j=1;j<=M;j++)
 90             scanf("%d",&D[i][j]);
 91         for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)
 92             scanf("%d",&E[i][j]);
 93         for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)
 94             scanf("%d",&F[i][j]);
 95 
 96         S=0,u=N+N+M+1,T=N+N+1+M+1,n=T;
 97         for(int i=1;i<=N;i++)
 98         {
 99             addEdge(S,i,1,0);
100             addEdge(N+i,T,1,0);
101             for(int j=1;j<=N;j++)
102             {
103                 if(i!=j&&tt[i]+E[i][j]<tt[j])
104                 {
105                     int c=(max(tt[i]+E[i][j],ss[j])-ss[j])*K;
106                     addEdge(i,N+j,1,c+F[i][j]);
107                 }
108             }
109         }
110         addEdge(S,u,M,0);
111         for(int i=1;i<=M;i++)
112         {
113             addEdge(u,N+N+i,1,0);
114             for(int j=1;j<=N;j++)
115             {
116                 if(C[j][i]<tt[j])
117                 {
118                     int c=(max(C[j][i],ss[j])-ss[j])*K;
119                     addEdge(N+N+i,N+j,1,c+D[j][i]);
120                 }
121             }
122         }
123         int flow,cost;
124         MCMF(S,T,cost,flow);
125         if(flow!=N)printf("-1\n");
126         else printf("%d\n",cost);
127     }
128     return 0;
129 }

转载于:https://www.cnblogs.com/taozi1115402474/p/9986060.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值