Learning:多路增广费用流

Learning

多路增广费用流

好吧,只有我觉得这玩意儿好像就是一个spfa标号的dicnic吗

参考dicnic,每次把bfs改成spfa,然后依据\(d_u \leqslant d_c + w(u,v)\)分层就可以了。。。

代码

/*
xsy2692
*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int N = 100 + 10;
const int maxn = 500 + 10;
const int INF = 0x3f3f3f3f;
const int Node = 10010;
const int E = 200000;
 
inline int rd()
{
    int x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x;
}
 
int R, C, n, A, B, xx[8], yy[8], Ans = 0, S, T;
char s[N][N];
 
int h[Node], ecnt;
struct enode{
  int v, n, w, c, op;
  enode() {}
  enode(int _v, int _n, int _w, int _c, int _op):v(_v), n(_n), w(_w), c(_c), op(_op) {}
}e[E << 1];
 
inline void addedge(int u, int v, int w, int c) {
//  cout << u << ' ' << v << ' ' << ((c >= INF) ? (-1) : (c)) << endl;
    ecnt ++; e[ecnt] = enode(v,h[u],w,c,ecnt + 1); h[u] = ecnt;
    ecnt ++; e[ecnt] = enode(u,h[v],0,- c,ecnt - 1); h[v] = ecnt;
}
 
int dist[Node], p[Node], flow = 0;
bool inq[Node];
int q[E];
inline int spfa() {
    int head, tail;
    head = tail = 1;
  memset(dist,0x3f,sizeof(dist));
  memset(inq,false,sizeof(inq));
  q[tail] = S; inq[S] = true;
  dist[S] = 0; p[S] = -1;
  while(head <= tail) {
    int u = q[head]; head ++;
    for(int i = h[u];~ i;i = e[i].n) {
      int v = e[i].v;
      if(e[i].w > 0 && dist[v] > dist[u] + e[i].c) {
        p[v] = e[i].op;
        dist[v] = dist[u] + e[i].c;
        if(!inq[v]) {
          inq[v] = true;
          q[++ tail] = v;
                }
            }
        }
        inq[u] = false;
    }
    if(dist[T] >= INF) return 0;
    return 1;
}
 
int cur[maxn];
 
int dfs(int u, int c) {
  if(u == T || c == 0) return c;
  inq[u] = 1;
  int tmp = 0;
  for(int i = cur[u];~ i;i = e[i].n) {
    cur[u] = i;
    int v = e[i].v;
    if(inq[v]) continue;
    if(dist[v] == dist[u] + e[i].c && e[i].w > 0) {
      int x = dfs(v,min(c,e[i].w));
      if(x) {
        e[i].w -= x; e[e[i].op].w += x;
        tmp += x; c -= x;
                Ans += x * e[i].c;
        if(!c) break;
            }
        }
    }
    return tmp;
}
 
int main() {
//  scanf("%d%d%d%d%d", &R, &C, &n, &A, &B);
  R = rd(); C = rd(); n = rd(); A = rd(); B = rd();
    memset(h,-1,sizeof(h));
    ecnt = 0;
    xx[0] = A; yy[0] = B;
    xx[1] = A; yy[1] = - B;
    xx[2] = - A; yy[2] = B;
    xx[3] = - A; yy[3] = - B;
    xx[4] = B; yy[4] = A;
    xx[5] = B; yy[5] = - A;
    xx[6] = - B; yy[6] = A;
    xx[7] = - B; yy[7] = - A;
    for(int i = 1;i <= R;i ++) {
      scanf("%s", s[i] + 1);
    }
    S = 0; T = R * C + 1;
    for(int i = 1;i <= n;i ++) {
      int x, y;
//    scanf("%d%d", &x, &y);
    x = rd(); y = rd();
      addedge(S,(x - 1) * C + y,1,0);
    }
    for(int i = 1;i <= n;i ++) {
      int x, y;
//    scanf("%d%d", &x, &y);
    x = rd(); y = rd();
      addedge((x - 1) * C + y,T,1,0);
    }
    for(int i = 1;i <= R;i ++) {
      for(int j = 1;j <= C;j ++) {
        if(s[i][j] == '*') continue;
        int id = (i - 1) * C + j;
        for(int k = 0;k < 8;k ++) {
          int dx = i + xx[k];
          int dy = j + yy[k];
          if(dx < 1 || dy < 1 || dx > R || dy > C || s[dx][dy] == '*') continue;
          addedge(id,(dx - 1) * C + dy,INF,1);
            }
        }
    }
    Ans = 0;
    while(spfa()) {
        for(int i = S;i <= T;i ++) cur[i] = h[i];
        memset(inq,0,sizeof(inq));
      int x = dfs(S,INF);
      if(x == 0) break;
      flow += x;
    }
    if(flow != n) Ans = -1;
    printf("%d\n", Ans);
  return 0;
}

什么你问我复杂度?O(松)

转载于:https://www.cnblogs.com/ezhjw/p/10027722.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值