HDU_4780_Candy Factory(最小费用流)

Candy Factory

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 382    Accepted Submission(s): 185



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
 

Source
 

题意:M 台机器生产 N 颗糖果,有如下规则

(1)生产每颗糖果的时间为[si, ti],如果从pi(si < pi < ti)开始,那么产生费用 K * (pi - si);

(2)每台机器开始使用时需要一个启动时间 C[i][j] 以及启动费用 D[i][j],代表 i 糖果触发 j 机器启动,需要时间C[i][j],花费D[i][j];

(3)当一台机器生产完 i 糖果后 可继续生产 j 糖果,期间需要一个缓冲时间为 E[i][j],花费 F[i][j];

现在问生产完所有糖果所花费的最小费用,若不能全部生产则输出 -1。


分析:最小费用流。直接按照规则建图,由于糖果与糖果之间可以连边,所以可以把糖果拆点,保证一颗糖果只生产一次。对于糖果 i 与糖果 j 之间的转换,连边 j -> i' 表示 j 可在 i 糖果之后生产。

建图:

(1)加入超级源点s(0),s 连向每颗糖果 i,连边 s -> i,容量为1,费用为0;

(2)加入超级汇点t(2 * N + M + 1),每台机器 i 连向 t,连边 i + 2 * N -> t,容量为1,费用为0;每颗糖果 j 连向 t,连边 N + j -> t,容量为1,费用为0;

(3)对于第二条规则,对于糖果 i、机器 j (C[i][j] < t[i]),如果 C[i][j] > s[i],那么 cost = D[i][j] + K * (C[i][j] - st[i]),否则 cost = D[i][j],连边 i -> 2 * N + j,容量为1,费用为cost;

(4)对于第三条规则,对于糖果 i、糖果 j (t[i] + E[i][j] < t[j]),如果 t[i] + E[i][j] > s[j],那么 cost = F[i][j] + K * (t[i] + E[i][j] - t[j]),否则 cost = F[i][j],连边 j -> N + i,容量为1,费用为cost。


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4780


代码清单:

/*******************************************************************************
 *** problem ID  : HDU_4780.cpp
 *** create time : Sat Oct 31 13:48:49 2015
 *** author name : nndxy
 *** author blog : http://blog.csdn.net/jhgkjhg_ugtdk77
 *** author motto: never loose enthusiasm for life, life is to keep on fighting!
 *******************************************************************************/

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

#define end() return 0

typedef long long ll;   
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxn = 300 + 5;
const int INF = 0x7f7f7f7f;

struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int w) : from(u), to(v), cap(c), flow(f), cost(w) {}
};

struct MCMF{
    int n, m, flow, cost;
    vector <Edge> edge; //边数的两倍
    vector <int> G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号
    int inq[maxn]; //是否在队列
    int d[maxn]; //Bellman-Ford
    int p[maxn]; //上一条弧
    int a[maxn]; //可改进量

    void init(int n){
        this -> n = n;
        for(int i = 0; i <=n ; i++) G[i].clear();
        edge.clear();
    }

    void addEdge(int from, int to, int cap, int cost){
        edge.push_back(Edge(from, to, cap, 0, cost));
        edge.push_back(Edge(to, from, 0, 0, -cost));
        m = edge.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BellmanFord(int s, int t, int& flow, int& cost){
        memset(d, INF, sizeof(d));
        memset(inq, 0, sizeof(inq));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

        queue <int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front(); q.pop();
            inq[u] = 0;
            for(int i = 0; i < G[u].size(); i++){
                Edge& e = edge[G[u][i]];
                if(e.cap > e.flow && d[e.to] > d[u] + e.cost){
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if(!inq[e.to]){
                        q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }

        if(d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        for(int u = t; u != s; u = edge[p[u]].from){
            edge[p[u]].flow += a[t];
            edge[p[u]^1].flow -= a[t];
        }
        return true;
    }

    //需要保证初始网络中没有负权圈
    void MincostMaxflow(int s, int t){
        this -> flow = 0, this -> cost = 0;
        while(BellmanFord(s, t, flow, cost));
    }
};

int N, M, K;
int st[maxn], tt[maxn];
int C[maxn][maxn], D[maxn][maxn];
int E[maxn][maxn], F[maxn][maxn];

MCMF mcmf;
int tail;

void input(){

	for(int i = 1; i <= N ; i++){
		scanf("%d%d", &st[i], &tt[i]);
	}

	for(int i = 1; i <= N; i++){
		for(int j = 1; j <= M; j++){
			scanf("%d", &C[i][j]);
		}
	}

	for(int i = 1; i <= N; i++){
		for(int j = 1; j <= M; j++){
			scanf("%d", &D[i][j]);
		}
	}

	for(int i = 1; i <= N; i++){
		for(int j = 1; j <= N; j++){
			scanf("%d", &E[i][j]);
		}
	}

	for(int i = 1; i <= N; i++){
		for(int j = 1; j <= N; j++){
			scanf("%d", &F[i][j]);
		}
	}
}

void createGraph(){

	tail = N + N + M + 1;
	mcmf.init(tail + 1);

	for(int i = 1; i <= N; i++){
		mcmf.addEdge(0, i, 1, 0);
		mcmf.addEdge(N + i, tail, 1, 0);
	}
	for(int i = 1; i <= M; i++){
		mcmf.addEdge(2 * N + i, tail, 1, 0);
	}

	for(int i = 1; i <= N; i++){
		for(int j = 1; j <= M; j++){
			if(C[i][j] >= tt[i]) continue;
			int cost = D[i][j];
			if(C[i][j] > st[i]) cost += K * (C[i][j] - st[i]);
			mcmf.addEdge(i, 2 * N + j, 1, cost);
		}
	}

	for(int i = 1; i <= N; i++){
		for(int j = 1; j <= N; j++){
			if(i == j) continue;
			if(tt[i] + E[i][j] >= tt[j]) continue;
			int cost = F[i][j];
			if(tt[i] + E[i][j] > st[j]) cost += K *(tt[i] + E[i][j] - st[j]);
			mcmf.addEdge(j, N + i, 1, cost);
		}
	}
}

void solve(){

	createGraph();
	mcmf.MincostMaxflow(0, tail);
	if(mcmf.flow < N) printf("-1\n");
	else printf("%d\n", mcmf.cost);
}

int main(){
	while(scanf("%d%d%d", &N, &M, &K) != EOF && N && M && K){
		input();
		solve();
	}	end();
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值