2013 Asia Hangzhou Regional Contest hdu4780 Candy Factory

参考:https://blog.csdn.net/sd_invol/article/details/15813671

要点

  1. 每个任务的结束时间是固定的,不受任何因素影响
  2. 机器只在最一开始有用,在那之后都是任务之间的转换

连边

将任务拆点,入点 i, 出点 i', 连边 (i, i' [1,1], 0)

设源点 s_, 汇点 t_

  1. 对于机器 \(i (i \in [1, m])\), 连 (s_, i, 1, 0),即流量为1,费用为0
    1. 对每个任务 \(j\)
      • 如果 \(C[i][j] \le ss[i]\),连 (i, j, 1, D[i][j])
      • 否则如果 \(C[i][j] < tt[j]\),连 (i, j, 1, D[i][j] + k*(C[i][j] - s[j]))
      • 否则不连边
  2. 对于每个任务 \(i(i\in[1,n])\),
    1. 连 (i, i', [1,1],0), 即流量在 [1,1]范围内,费用为0的边
    2. 连 (i',t_, 1, 0)
    3. 对于另一个任务 j,考虑 i -> j 的转换, 即 \(endTime = tt[i] + E[i][j]\)
      • 如果 \(endTime \le ss[j]\), 连(i', j, 1, F[i][j])
      • 否则如果 \(endTime \lt tt[j]\) ,连 (i', j, 1, F[i][j] + k * (endTime - ss[j]))
      • 否则不连边

然后对该网络求有源汇的上下界网络流即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
#define dbg(x...) do { cout << "\033[32;1m" << #x <<" -> "; err(x); } while (0)
void err() { cout << "\033[39;0m" << endl; }
template<class T, class... Ts> void err(const T& arg,const Ts&... args) { cout << arg << " "; err(args...); }
const int N = 300 + 10;
const int M = 200010;
int n, m, k, s_, t_, s, t;
int ss[N], tt[N];
int C[N][N], D[N][N], E[N][N], F[N][N];
int head[N], nxt[M], ver[M], edge[M], cost[M], tot;
int d[N], v[N], incf[N], pre[N];
int ans, maxflow;
void add(int x, int y, int z, int c){
    ver[++tot] = y, edge[tot] = z, nxt[tot] = head[x], head[x] = tot, cost[tot] = c;
    ver[++tot] = x, edge[tot] = 0, nxt[tot] = head[y], head[y] = tot, cost[tot] = -c;
}
bool spfa(){
    queue<int> q;
    memset(d, 0x3f, sizeof d);
    memset(v, 0, sizeof v);
    q.push(s);
    d[s] = 0, v[s] = 1;
    incf[s] = inf;
    while(q.size()){
        int x = q.front();
        q.pop();
        v[x] = 0;
        for (int i = head[x]; i;i=nxt[i]){
            if(!edge[i])
                continue;
            int y = ver[i];
            if(d[y] > d[x] + cost[i]){
                d[y] = d[x] + cost[i];
                incf[y] = min(incf[x], edge[i]);
                pre[y] = i;
                if(!v[y])
                    v[y] = 1, q.push(y);
            }
        }
    }
    if(d[t] == inf)
        return false;
    return true;
}

void update(){
    int x = t;
    while(x != s){
        int i = pre[x];
        edge[i] -= incf[t];
        edge[i ^ 1] += incf[t];
        x = ver[i ^ 1];
    }
    maxflow += incf[t];
    ans += d[t] * incf[t];
}


int main(){
    while(~scanf("%d%d%d", &n, &m, &k)){
        if(n == 0 && m == 0 && k == 0)break;
        tot = 1;
        s_ = n + n + m + 1, t_ = s_ + 1, s = t_ + 1, t = s + 1;
        for(int i=1;i<=t;i++) head[i] = 0;
        ans = 0, maxflow = 0;
        for(int i=1;i<=n;i++) scanf("%d%d", &ss[i], &tt[i]);
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d", &C[j][i]);
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d", &D[j][i]);
        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]);
        
        // (i, i+n, [1,1], 0)
        // s 向 出点 (s, i+n, 1, 0)
        // 入点 向 t (i, t, 1, 0)
        // 出点向t_ (i+n, t_, 1, 0)
        for(int i=1;i<=n;i++){
            add(s, i+n, 1, 0);
            add(i, t, 1, 0);
            add(i+n, t_, 1, 0);
        }
        // s_-> 机器连边 流量1, 费用0
        for(int i=1;i<=m;i++){
            add(s_, n+n+i, 1, 0);
        }
        // 机器与任务连边
        for(int i=1;i<=m;i++){
            int id = 2 * n + i;
            for(int j=1;j<=n;j++){
                if(C[i][j] <= ss[j]){ //在ss[j]之前就可以准备好
                    add(id, j, 1, D[i][j]);
                } else if(C[i][j] < tt[j]){ // 无法在tt[j] 之前准备好
                    add(id, j, 1, D[i][j]+k*(C[i][j]-ss[j]));
                }
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i == j) continue;
                int endTime = tt[i] + E[i][j];
                if(endTime <= ss[j]){
                    add(i + n, j, 1, F[i][j]);
                } else if(endTime < tt[j]) {
                    add(i + n, j, 1, F[i][j] + k * (endTime - ss[j]));
                }
            }
        }
        add(t_, s_, inf, 0);
        while(spfa()) update();
        if(maxflow != n) puts("-1");
        else printf("%d\n", ans);
    }
    return 0;
}
posted @ 2020-04-25 23:29  kpole  阅读(106)  评论(0编辑  收藏  举报