读书人

图论算法模板拾掇

发布时间: 2013-09-28 10:01:20 作者: rapoo

图论算法模板整理

//无向图的双连通分量int pre[maxn], iscut[maxn], bccno[maxn], dfs_clock, bcc_cnt; // 割顶的bccno无意义struct Edge { int u, v; };vector<int> G[maxn], bcc[maxn];stack<Edge> S;int dfs(int u, int fa) {  int lowu = pre[u] = ++dfs_clock;  int child = 0;  for(int i = 0; i < G[u].size(); i++) {    int v = G[u][i];    Edge e = (Edge){u, v};    if(!pre[v]) { // 没有访问过v      S.push(e);      child++;      int lowv = dfs(v, u);      lowu = min(lowu, lowv); // 用后代的low函数更新自己      if(lowv >= pre[u]) {        iscut[u] = true;        bcc_cnt++; bcc[bcc_cnt].clear();        for(;;) {          Edge x = S.top(); S.pop();          if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; }          if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; }          if(x.u == u && x.v == v) break;        }      }    }    else if(pre[v] < pre[u] && v != fa) {      S.push(e);      lowu = min(lowu, pre[v]); // 用反向边更新自己    }  }  if(fa < 0 && child == 1) iscut[u] = 0;  return lowu;}void find_bcc(int n) {  // 调用结束后S保证为空,所以不用清空  memset(pre, 0, sizeof(pre));  memset(iscut, 0, sizeof(iscut));  memset(bccno, 0, sizeof(bccno));  dfs_clock = bcc_cnt = 0;  for(int i = 0; i < n; i++)    if(!pre[i]) dfs(i, -1); };//无向图求桥 & 双连通分量int dfs(int u, int fa)  {      int lowu = pre[u] = ++dfs_clock;      int nc = G[u].size();      REP(i, nc)      {          int v = edges[G[u][i]].to;          if(!pre[v])          {              int lowv = dfs(v, u);              lowu = min(lowu, lowv);              if(lowv > pre[u]) edges[G[u][i]].flag = 1, edges[G[u][i]^1].flag = 1; //标记所有桥          }          else if(pre[v] < pre[u] && v != fa) lowu = min(lowu, pre[v]);      }      return low[u] = lowu;  }    void dfs1(int u)  {      bccno[u] = bcc_cnt;      int nc = G[u].size();      REP(i, nc)      {          int v = edges[G[u][i]].to;          if(!bccno[v] && edges[G[u][i]].flag != 1) dfs1(v);//不经过桥      }  }    void find_bcc()  {      CLR(pre, 0); CLR(bccno, 0);      dfs_clock = bcc_cnt = 0;      REP(i, n) if(!pre[i]) dfs(i, -1);      REP(i, n) if(!bccno[i]) bcc_cnt++, dfs1(i);  }  //有向图的强连通分量vector<int> G[maxn];int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;stack<int> S;void dfs(int u) {  pre[u] = lowlink[u] = ++dfs_clock;  S.push(u);  for(int i = 0; i < G[u].size(); i++) {    int v = G[u][i];    if(!pre[v]) {      dfs(v);      lowlink[u] = min(lowlink[u], lowlink[v]);    } else if(!sccno[v]) {      lowlink[u] = min(lowlink[u], pre[v]);    }  }  if(lowlink[u] == pre[u]) {    scc_cnt++;    for(;;) {      int x = S.top(); S.pop();      sccno[x] = scc_cnt;      if(x == u) break;    }  }}void find_scc(int n) {  dfs_clock = scc_cnt = 0;  memset(sccno, 0, sizeof(sccno));  memset(pre, 0, sizeof(pre));  for(int i = 0; i < n; i++)    if(!pre[i]) dfs(i);};//无向图的欧拉回路 保存在G中void add(int u, int v){    g[u][v] = g[v][u] = 1;     degree[u]++, degree[v]++; }void Euler()  {      FF(i, 1, n+1) if(degree[i])      {          int u = i;          while(true)          {              FF(j, 1, n+1) if(g[u][j] && g[j][u])              {                  g[j][u] = 0;                  degree[u]--, degree[i]--;                  u = j;                  break;              }              if(u == i) break;          }      }  } //2-sat dfs版本struct TwoSAT {  int n;  vector<int> G[maxn*2];  bool mark[maxn*2];  int S[maxn*2], c;  bool dfs(int x) {    if (mark[x^1]) return false;    if (mark[x]) return true;    mark[x] = true;    S[c++] = x;    for (int i = 0; i < G[x].size(); i++)      if (!dfs(G[x][i])) return false;    return true;  }  void init(int n) {    this->n = n;    for (int i = 0; i < n*2; i++) G[i].clear();    memset(mark, 0, sizeof(mark));  }  // x = xval or y = yval  void add_clause(int x, int xval, int y, int yval) {    x = x * 2 + xval;    y = y * 2 + yval;    G[x^1].push_back(y);    G[y^1].push_back(x);  }  bool solve() {    for(int i = 0; i < n*2; i += 2)      if(!mark[i] && !mark[i+1]) {        c = 0;        if(!dfs(i)) {          while(c > 0) mark[S[--c]] = false;          if(!dfs(i+1)) return false;        }      }    return true;  }};//堆优化的Dijkstrastruct Edge {  int from, to, dist;};struct HeapNode {  int d, u;  bool operator < (const HeapNode& rhs) const {    return d > rhs.d;  }};struct Dijkstra {  int n, m;  vector<Edge> edges;  vector<int> G[maxn];  bool done[maxn];    // 是否已永久标号  int d[maxn];        // s到各个点的距离  int p[maxn];        // 最短路中的上一条弧  void init(int n) {    this->n = n;    for(int i = 0; i < n; i++) G[i].clear();    edges.clear();  }  void AddEdge(int from, int to, int dist) {    edges.push_back((Edge){from, to, dist});    m = edges.size();    G[from].push_back(m-1);  }  void dijkstra(int s) {    priority_queue<HeapNode> Q;    for(int i = 0; i < n; i++) d[i] = INF;    d[s] = 0;    memset(done, 0, sizeof(done));    Q.push((HeapNode){0, s});    while(!Q.empty()) {      HeapNode x = Q.top(); Q.pop();      int u = x.u;      if(done[u]) continue;      done[u] = true;      for(int i = 0; i < G[u].size(); i++) {        Edge& e = edges[G[u][i]];        if(d[e.to] > d[u] + e.dist) {          d[e.to] = d[u] + e.dist;          p[e.to] = G[u][i];          Q.push((HeapNode){d[e.to], e.to});        }      }    }  }  // dist[i]为s到i的距离,paths[i]为s到i的最短路径(经过的结点列表,包括s和t)  void GetShortestPaths(int s, int* dist, vector<int>* paths) {    dijkstra(s);    for(int i = 0; i < n; i++) {      dist[i] = d[i];      paths[i].clear();      int t = i;      paths[i].push_back(t);      while(t != s) {        paths[i].push_back(edges[p[t]].from);        t = edges[p[t]].from;      }      reverse(paths[i].begin(), paths[i].end());    }  }};//spfa判负环struct Edge {  int from, to;  double dist;};struct spfa {  int n, m;  vector<Edge> edges;  vector<int> G[maxn];  bool inq[maxn];     // 是否在队列中  double d[maxn];     // s到各个点的距离  int p[maxn];        // 最短路中的上一条弧  int cnt[maxn];      // 进队次数  void init(int n) {    this->n = n;    for(int i = 0; i < n; i++) G[i].clear();    edges.clear();  }  void AddEdge(int from, int to, double dist) {    edges.push_back((Edge){from, to, dist});    m = edges.size();    G[from].push_back(m-1);  }  bool negativeCycle() {    queue<int> Q;    memset(inq, 0, sizeof(inq));    memset(cnt, 0, sizeof(cnt));    for(int i = 0; i < n; i++) { d[i] = 0; inq[0] = true; Q.push(i); }    while(!Q.empty()) {      int u = Q.front(); Q.pop();      inq[u] = false;      for(int i = 0; i < G[u].size(); i++) {        Edge& e = edges[G[u][i]];        if(d[e.to] > d[u] + e.dist) {          d[e.to] = d[u] + e.dist;          p[e.to] = G[u][i];          if(!inq[e.to]) { Q.push(e.to); inq[e.to] = true; if(++cnt[e.to] > n) return true; }        }      }    }    return false;  }};//kruskal求次小生成树 maxcost[i][j]为i->j的瓶颈路 //对于MST边u, v maxcost[u][v] = 0int n, m, x[maxn], y[maxn], p[maxn];int pa[maxn];int findset(int x) { return pa[x] != x ? pa[x] = findset(pa[x]) : x; } //G保存MST C保存MST边权vector<int> G[maxn];vector<double> C[maxn];struct Edge {  int x, y;  double d;  bool operator < (const Edge& rhs) const {    return d < rhs.d;  }};Edge e[maxn*maxn];double maxcost[maxn][maxn];vector<int> nodes;void dfs(int u, int fa, double facost) {  for(int i = 0; i < nodes.size(); i++) {    int x = nodes[i];    maxcost[u][x] = maxcost[x][u] = max(maxcost[x][fa], facost);  }  nodes.push_back(u);  for(int i = 0; i < G[u].size(); i++) {    int v = G[u][i];    if(v != fa) dfs(v, u, C[u][i]);  }}double MST() {  sort(e, e+m);  for(int i = 0; i < n; i++) { pa[i] = i; G[i].clear(); C[i].clear(); }  int cnt = 0;  double ans = 0;  for(int i = 0; i < m; i++) {    int x = e[i].x, y = e[i].y, u = findset(x), v = findset(y);    double d = e[i].d;    if(u != v) {      pa[u] = v;      G[x].push_back(y); C[x].push_back(d);      G[y].push_back(x); C[y].push_back(d);      ans += d;      if(++cnt == n-1) break;    }  }  return ans;}//prim求次小生成树//use[u][v] = 2时,边<u, v>在MST上//use[u][v] = 1时,原图存在边<u, v>。//f[u][v]表示u->v的最小瓶颈路 初始化为0double prim()  {      int pre[maxn] = {-1};      bool vis[maxn] = {0};      double d[maxn], ret = 0;      FF(i, 1, n+1) d[i] = INF;   d[1] = 0;      FF(i, 1, n+1)      {          int pos;          double tmp = INF;          FF(j, 1, n+1) if(!vis[j] && d[j] < tmp) tmp = d[j], pos = j;          if(pre[pos] != -1)          {              use[pre[pos]][pos] = use[pos][pre[pos]] = 2;              FF(j, 1, n+1) if(vis[j]) f[pos][j] = f[j][pos] = max(f[j][pre[pos]], g[pre[pos]][pos]);          }          vis[pos] = 1;          ret += d[pos];          FF(j, 1, n+1) if(!vis[j] && use[pos][j] && g[pos][j] < d[j]) d[j] = g[pos][j], pre[j] = pos;      }      return ret;  }//LCAstruct LCA {  int n;  int fa[maxn];   // 父亲数组  int cost[maxn]; // 和父亲的费用  int L[maxn];    // 层次(根节点层次为0)  int anc[maxn][logmaxn];     // anc[p][i]是结点p的第2^i级父亲。anc[i][0] = fa[i]  int maxcost[maxn][logmaxn]; // maxcost[p][i]是i和anc[p][i]的路径上的最大费用  // 预处理,根据fa和cost数组求出anc和maxcost数组  void preprocess() {    for(int i = 0; i < n; i++) {      anc[i][0] = fa[i]; maxcost[i][0] = cost[i];      for(int j = 1; (1 << j) < n; j++) anc[i][j] = -1;    }       for(int j = 1; (1 << j) < n; j++)      for(int i = 0; i < n; i++)        if(anc[i][j-1] != -1) {          int a = anc[i][j-1];          anc[i][j] = anc[a][j-1];          maxcost[i][j] = max(maxcost[i][j-1], maxcost[a][j-1]);        }  }  // 求p到q的路径上的最大权  int query(int p, int q) {    int tmp, log, i;    if(L[p] < L[q]) swap(p, q);    for(log = 1; (1 << log) <= L[p]; log++); log--;    int ans = -INF;    for(int i = log; i >= 0; i--)      if (L[p] - (1 << i) >= L[q]) { ans = max(ans, maxcost[p][i]); p = anc[p][i];}       if (p == q) return ans; // LCA为p       for(int i = log; i >= 0; i--)      if(anc[p][i] != -1 && anc[p][i] != anc[q][i]) {        ans = max(ans, maxcost[p][i]); p = anc[p][i];        ans = max(ans, maxcost[q][i]); q = anc[q][i];      }    ans = max(ans, cost[p]);    ans = max(ans, cost[q]);    return ans; // LCA为fa[p](它也等于fa[q])  }  };//固定根的最小树型图,邻接矩阵写法struct MDST {    int n;  int w[maxn][maxn]; // 边权  int vis[maxn];     // 访问标记,仅用来判断无解  int ans;           // 计算答案  int removed[maxn]; // 每个点是否被删除  int cid[maxn];     // 所在圈编号  int pre[maxn];     // 最小入边的起点  int iw[maxn];      // 最小入边的权值  int max_cid;       // 最大圈编号  void init(int n) {    this->n = n;    for(int i = 0; i < n; i++)      for(int j = 0; j < n; j++) w[i][j] = INF;  }  void AddEdge(int u, int v, int cost) {    w[u][v] = min(w[u][v], cost); // 重边取权最小的  }  // 从s出发能到达多少个结点  int dfs(int s) {    vis[s] = 1;    int ans = 1;    for(int i = 0; i < n; i++)      if(!vis[i] && w[s][i] < INF) ans += dfs(i);    return ans;  }  // 从u出发沿着pre指针找圈  bool cycle(int u) {    max_cid++;    int v = u;    while(cid[v] != max_cid) { cid[v] = max_cid; v = pre[v]; }    return v == u;  }  // 计算u的最小入弧,入弧起点不得在圈c中  void update(int u) {    iw[u] = INF;    for(int i = 0; i < n; i++)      if(!removed[i] && w[i][u] < iw[u]) {        iw[u] = w[i][u];        pre[u] = i;      }  }  // 根结点为s,如果失败则返回false  bool solve(int s) {        memset(vis, 0, sizeof(vis));    if(dfs(s) != n) return false;    memset(removed, 0, sizeof(removed));    memset(cid, 0, sizeof(cid));    for(int u = 0; u < n; u++) update(u);    pre[s] = s; iw[s] = 0; // 根结点特殊处理    ans = max_cid = 0;    for(;;) {      bool have_cycle = false;      for(int u = 0; u < n; u++) if(u != s && !removed[u] && cycle(u)){        have_cycle = true;        // 以下代码缩圈,圈上除了u之外的结点均删除        int v = u;        do {          if(v != u) removed[v] = 1;          ans += iw[v];          // 对于圈外点i,把边i->v改成i->u(并调整权值);v->i改为u->i          // 注意圈上可能还有一个v'使得i->v'或者v'->i存在,因此只保留权值最小的i->u和u->i          for(int i = 0; i < n; i++) if(cid[i] != cid[u] && !removed[i]) {            if(w[i][v] < INF) w[i][u] = min(w[i][u], w[i][v]-iw[v]);            w[u][i] = min(w[u][i], w[v][i]);            if(pre[i] == v) pre[i] = u;          }          v = pre[v];        } while(v != u);                update(u);        break;      }      if(!have_cycle) break;    }    for(int i = 0; i < n; i++)      if(!removed[i]) ans += iw[i];    return true;  }};//KM int W[maxn][maxn], n;int Lx[maxn], Ly[maxn]; // 顶标int left[maxn];         // left[i]为右边第i个点的匹配点编号bool S[maxn], T[maxn];   // S[i]和T[i]为左/右第i个点是否已标记bool match(int i){  S[i] = true;  for(int j = 1; j <= n; j++) if (Lx[i]+Ly[j] == W[i][j] && !T[j]){    T[j] = true;    if (!left[j] || match(left[j])){      left[j] = i;      return true;    }  }  return false;}void update(){  int a = INF;  for(int i = 1; i <= n; i++) if(S[i])    for(int j = 1; j <= n; j++) if(!T[j])      a = min(a, Lx[i]+Ly[j] - W[i][j]);  for(int i = 1; i <= n; i++) {    if(S[i]) Lx[i] -= a;    if(T[i]) Ly[i] += a;  }}void KM() {  for(int i = 1; i <= n; i++) {    left[i] = Lx[i] = Ly[i] = 0;    for(int j = 1; j <= n; j++)      Lx[i] = max(Lx[i], W[i][j]);  }  for(int i = 1; i <= n; i++) {    for(;;) {      for(int j = 1; j <= n; j++) S[j] = T[j] = false;      if(match(i)) break; else update();    }  }}// 二分图最大基数匹配,邻接矩阵写法  struct BPM {  int n, m;               // 左右顶点个数  int G[maxn][maxn];      // 邻接表  int left[maxn];         // left[i]为右边第i个点的匹配点编号,-1表示不存在  bool T[maxn];           // T[i]为右边第i个点是否已标记  void init(int n, int m) {    this->n = n;    this->m = m;    memset(G, 0, sizeof(G));  }  bool match(int u){    for(int v = 0; v < m; v++) if(G[u][v] && !T[v]) {      T[v] = true;      if (left[v] == -1 || match(left[v])){        left[v] = u;        return true;      }    }    return false;  }  // 求最大匹配  int solve() {    memset(left, -1, sizeof(left));    int ans = 0;    for(int u = 0; u < n; u++) { // 从左边结点u开始增广      memset(T, 0, sizeof(T));      if(match(u)) ans++;    }    return ans;  }};// 二分图最大基数匹配求覆盖集struct BPM {    int n, m;               // 左右顶点个数    vector<int> G[maxn];    // 邻接表    int left[maxn];         // left[i]为右边第i个点的匹配点编号,-1表示不存在    bool T[maxn];           // T[i]为右边第i个点是否已标记      int right[maxn];        // 求最小覆盖用    bool S[maxn];           // 求最小覆盖用      void init(int n, int m) {      this->n = n;      this->m = m;      for(int i = 0; i < n; i++) G[i].clear();    }      void AddEdge(int u, int v) {      G[u].push_back(v);    }      bool match(int u){      S[u] = true;      for(int i = 0; i < G[u].size(); i++) {        int v = G[u][i];        if (!T[v]){          T[v] = true;          if (left[v] == -1 || match(left[v])){            left[v] = u;            right[u] = v;            return true;          }        }      }      return false;    }      // 求最大匹配    int solve() {      memset(left, -1, sizeof(left));      memset(right, -1, sizeof(right));      int ans = 0;      for(int u = 0; u < n; u++) { // 从左边结点u开始增广        memset(S, 0, sizeof(S));        memset(T, 0, sizeof(T));        if(match(u)) ans++;      }      return ans;    }      // 求最小覆盖。X和Y为最小覆盖中的点集    int mincover(vector<int>& X, vector<int>& Y) {      int ans = solve();      memset(S, 0, sizeof(S));      memset(T, 0, sizeof(T));      for(int u = 0; u < n; u++)        if(right[u] == -1) match(u); // 从所有X未盖点出发增广      for(int u = 0; u < n; u++)        if(!S[u]) X.push_back(u); // X中的未标记点      for(int v = 0; v < m; v++)        if(T[v]) Y.push_back(v);  // Y中的已标记点     return ans;    }  };//ISAPstruct Edge {    int from, to, cap, flow;  };bool operator < (const Edge& a, const Edge& b) {    return a.from < b.from || (a.from == b.from && a.to < b.to);  }    struct ISAP {    int n, m, s, t;    vector<Edge> edges;    vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号    bool vis[maxn];        // BFS使用    int d[maxn];           // 从起点到i的距离    int cur[maxn];        // 当前弧指针    int p[maxn];          // 可增广路上的上一条弧    int num[maxn];        // 距离标号计数      void AddEdge(int from, int to, int cap) {      edges.push_back((Edge){from, to, cap, 0});      edges.push_back((Edge){to, from, 0, 0});      m = edges.size();      G[from].push_back(m-2);      G[to].push_back(m-1);    }      bool BFS() {      memset(vis, 0, sizeof(vis));      queue<int> Q;      Q.push(t);      vis[t] = 1;      d[t] = 0;      while(!Q.empty()) {        int x = Q.front(); Q.pop();        for(int i = 0; i < G[x].size(); i++) {          Edge& e = edges[G[x][i]^1];          if(!vis[e.from] && e.cap > e.flow) {            vis[e.from] = 1;            d[e.from] = d[x] + 1;            Q.push(e.from);          }        }      }      return vis[s];    }      void ClearAll(int n) {      this->n = n;      for(int i = 0; i < n; i++) G[i].clear();      edges.clear();    }      void ClearFlow() {      for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;        }      int Augment() {      int x = t, a = INF;      while(x != s) {        Edge& e = edges[p[x]];        a = min(a, e.cap-e.flow);        x = edges[p[x]].from;      }      x = t;      while(x != s) {        edges[p[x]].flow += a;        edges[p[x]^1].flow -= a;        x = edges[p[x]].from;      }      return a;    }      int Maxflow(int s, int t, int need) {      this->s = s; this->t = t;      int flow = 0;      BFS();      memset(num, 0, sizeof(num));      for(int i = 0; i < n; i++) num[d[i]]++;      int x = s;      memset(cur, 0, sizeof(cur));      while(d[s] < n) {        if(x == t) {          flow += Augment();          if(flow >= need) return flow;          x = s;        }        int ok = 0;        for(int i = cur[x]; i < G[x].size(); i++) {          Edge& e = edges[G[x][i]];          if(e.cap > e.flow && d[x] == d[e.to] + 1) { // Advance            ok = 1;            p[e.to] = G[x][i];            cur[x] = i; // 注意            x = e.to;            break;          }        }        if(!ok) { // Retreat          int m = n-1; // 初值注意          for(int i = 0; i < G[x].size(); i++) {            Edge& e = edges[G[x][i]];            if(e.cap > e.flow) m = min(m, d[e.to]);          }          if(--num[d[x]] == 0) break;          num[d[x] = m+1]++;          cur[x] = 0; // 注意          if(x != s) x = edges[p[x]].from;        }      }      return flow;    }      vector<int> Mincut() { // call this after maxflow      BFS();      vector<int> ans;      for(int i = 0; i < edges.size(); i++) {        Edge& e = edges[i];        if(!vis[e.from] && vis[e.to] && e.cap > 0) ans.push_back(i);      }      return ans;    }      void Reduce() {      for(int i = 0; i < edges.size(); i++) edges[i].cap -= edges[i].flow;    }      void print() {      printf("Graph:\n");      for(int i = 0; i < edges.size(); i++)        printf("%d->%d, %d, %d\n", edges[i].from, edges[i].to , edges[i].cap, edges[i].flow);    }};//Dinicstruct Edge {    int from, to, cap, flow;  };  bool operator < (const Edge& a, const Edge& b) {    return a.from < b.from || (a.from == b.from && a.to < b.to);  }struct Dinic {    int n, m, s, t;    vector<Edge> edges;    // 边数的两倍    vector<int> G[maxn];   // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号    bool vis[maxn];        // BFS使用    int d[maxn];           // 从起点到i的距离    int cur[maxn];         // 当前弧指针      void ClearAll(int n) {      for(int i = 0; i < n; i++) G[i].clear();      edges.clear();    }      void ClearFlow() {      for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;        }      void AddEdge(int from, int to, int cap) {      edges.push_back((Edge){from, to, cap, 0});      edges.push_back((Edge){to, from, 0, 0});      m = edges.size();      G[from].push_back(m-2);      G[to].push_back(m-1);    }      bool BFS() {      memset(vis, 0, sizeof(vis));      queue<int> Q;      Q.push(s);      vis[s] = 1;      d[s] = 0;      while(!Q.empty()) {        int x = Q.front(); Q.pop();        for(int i = 0; i < G[x].size(); i++) {          Edge& e = edges[G[x][i]];          if(!vis[e.to] && e.cap > e.flow) {            vis[e.to] = 1;            d[e.to] = d[x] + 1;            Q.push(e.to);          }        }      }      return vis[t];    }      int DFS(int x, int a) {      if(x == t || a == 0) return a;      int flow = 0, f;      for(int& i = cur[x]; i < G[x].size(); i++) {        Edge& e = edges[G[x][i]];        if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {          e.flow += f;          edges[G[x][i]^1].flow -= f;          flow += f;          a -= f;          if(a == 0) break;        }      }      return flow;    }      int Maxflow(int s, int t) {      this->s = s; this->t = t;      int flow = 0;      while(BFS()) {        memset(cur, 0, sizeof(cur));        flow += DFS(s, INF);      }      return flow;    }  };//MCMFstruct Edge {    int from, to, cap, flow, cost;  };struct MCMF {    int n, m, s, t;    vector<Edge> edges;    vector<int> G[maxn];    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();      edges.clear();    }      void AddEdge(int from, int to, int cap, int cost) {      edges.push_back((Edge){from, to, cap, 0, cost});      edges.push_back((Edge){to, from, 0, 0, -cost});      m = edges.size();      G[from].push_back(m-2);      G[to].push_back(m-1);    }      bool BellmanFord(int s, int t, LL& ans) {      for(int i = 0; i < n; i++) d[i] = INF;      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 = edges[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;//s-t不连通 失败退出      if(d[t] > 0) return false;//不固定流量的最小费用流      ans += (LL)d[t] * (LL)a[t];      int u = t;      while(u != s) {        edges[p[u]].flow += a[t];        edges[p[u]^1].flow -= a[t];        u = edges[p[u]].from;            }      return true;    }      // 需要保证初始网络中没有负权圈    LL Mincost(int s, int t) {      LL cost = 0;      while(BellmanFord(s, t, cost));      return cost;    }    };


读书人网 >其他相关

热点推荐