[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\n", ans);
}
int main() {
  // freopen("input", "r", stdin);
  solve();
}

posted on 2017-02-20 10:52  蒟蒻konjac  阅读(127)  评论(0编辑  收藏  举报