zoukankan      html  css  js  c++  java
  • 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(iin[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 << "33[32;1m" << #x <<" -> "; err(x); } while (0)
    void err() { cout << "33[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
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/1625--H/p/12776228.html
Copyright © 2011-2022 走看看