• [bzoj2245][SDOI2011]工作安排——费用流


    题目大意:

    传送门

    题解:

    很容易建模,把每一个工作人员拆成两个点,由第一个点向第二个点连S+1条边即可。
    这水题没什么难度,主要是longlong卡的丧心病狂。。。

    代码

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const ll maxn = 2550;
    const ll maxv = maxn * 10;
    const ll inf = 1000000000000;
    ll dist[maxv], inq[maxv], pree[maxv], fl[maxv];
    struct edge {
      ll from;
      ll to;
      ll cap;
      ll cost;
    };
    vector<edge> edges;
    vector<ll> G[maxv];
    ll n, m, a[maxn][maxn], c[maxn], v;
    void add_edge(ll from, ll to, ll cap, ll cost) {
      edges.push_back((edge){from, to, cap, cost});
      edges.push_back((edge){to, from, 0, -cost});
      ll m = edges.size();
      G[from].push_back(m - 2);
      G[to].push_back(m - 1);
    }
    bool spfa(ll s, ll t, ll &cost) {
      for (int i = 0; i < v; i++)
        dist[i] = inf;
      memset(inq, 0, sizeof(inq));
      memset(pree, 0, sizeof(pree));
      memset(fl, 0, sizeof(fl));
      queue<ll> q;
      fl[s] = inf;
      dist[s] = 0, inq[s] = 1;
      q.push(s);
      while (!q.empty()) {
        ll u = q.front();
        q.pop();
        inq[u] = 0;
        for (int i = 0; i < G[u].size(); i++) {
          edge &e = edges[G[u][i]];
          if (e.cap > 0 && dist[e.to] > dist[u] + e.cost) {
            dist[e.to] = dist[u] + e.cost;
            pree[e.to] = G[u][i];
            fl[e.to] = min(fl[u], e.cap);
            if (!inq[e.to]) {
              q.push(e.to);
              inq[e.to] = 1;
            }
          }
        }
      }
      if (dist[t] >= inf)
        return false;
      ll flow = fl[t];
      cost += flow * dist[t];
      ll u = t;
      while (!u == s) {
        edges[pree[u]].cap -= flow;
        edges[pree[u] ^ 1].cap += flow;
        u = edges[pree[u]].from;
      }
      return true;
    }
    ll mcmf(int s, int t) {
      ll cost = 0;
      while (spfa(s, t, cost))
        ;
      return cost;
    }
    void solve() {
      // 1-m:员工
      // m+1~m+n 产品
      // m+n+1~m+n+m 拆点后的员工
      scanf("%lld %lld", &m, &n);
      ll s = 0, t = n + m + m + 1;
      v = t + 1;
    
      for (int i = 1; i <= n; i++) {
        scanf("%lld", &c[i]);
        add_edge(m + i, t, c[i], 0);
      }
      for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++) {
          int x;
          scanf("%d", &x);
          if (x)
            add_edge(i, j + m, inf, 0);
        }
      for (int i = 1; i <= m; i++) {
        add_edge(s, n + m + i, inf, 0);
        ll s;
        scanf("%lld", &s);
        ll T[maxn];
        T[0] = 0;
        for (int j = 1; j <= s; j++)
          scanf("%lld", &T[j]);
        for (int j = 1; j <= s; j++) {
          ll y;
          scanf("%lld", &y);
          add_edge(n + m + i, i, T[j] - T[j - 1], y);
        }
        scanf("%lld", &s);
        add_edge(n + m + i, i, inf, s);
      }
      ll ans = mcmf(s, t);
      printf("%lld
    ", ans);
    }
    int main() {
      // freopen("input", "r", stdin);
      solve();
    }
    
  • 相关阅读:
    挺喜欢的一幅摄影作品,不知道作者 不知道出处...
    使用触发器来监控表的使用情况
    SQL Server 针对表的只读权限分配
    tnslsnr.exe进程占用大量内存的解决.
    记录一次MYSQL的备份(浅尝辄止型)
    记录temp被撑爆的一次SQL tuning
    Bug 5880921 V$SYSMETRIC_HISTORY 的时间错乱
    sqlite3学习记录
    指针 数组指针 指针数组 函数指针等说明。
    c/c++ 运算符 优先级 结合性 记录
  • 原文地址:https://www.cnblogs.com/gengchen/p/6418544.html
Copyright © 2020-2023  润新知