poj 1459 多源汇网络流 ISAP

题意:

给n个点,m条边,有np个源点,nc个汇点,求最大流

思路:

超级源点把全部源点连起来。边权是该源点的最大同意值;

全部汇点和超级汇点连接起来,边权是该汇点的最大同意值。

跑最大流

code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
using namespace std;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))

typedef pair<int,int> pii;
typedef long long LL;
//------------------------------
const int maxn = 205;
const int maxm = 205 * 205;
const int max_nodes = maxn;

struct Edge{
      int from, to;
      int capacity, flow;
      Edge(){}
      Edge(int from_, int to_, int capacity_, int flow_){
            from = from_;
            to = to_;
            capacity = capacity_;
            flow = flow_;
      }
};
Edge edges[maxm];
int cnte;
vector<int> g[maxn];
void graph_init(){
      cnte = 0;
      for(int i = 0; i < maxn; i++) g[i].clear();
}

void add_Edge(int from, int to, int cap){
      edges[cnte].from = from;
      edges[cnte].to = to;
      edges[cnte].capacity = cap;
      edges[cnte].flow = 0;
      g[from].push_back(cnte);
      cnte++;
      edges[cnte].from = to;
      edges[cnte].to = from;
      edges[cnte].capacity = 0;
      edges[cnte].flow = 0;
      g[to].push_back(cnte);
      cnte++;
}

int source;         // 源点
int sink;           // 汇点
int p[maxn];   // 可增广路上的上一条弧的编号
int num[maxn]; // 和 t 的最短距离等于 i 的节点数量
int cur[maxn]; // 当前弧下标
int d[maxn];   // 残量网络中节点 i 到汇点 t 的最短距离
bool visited[maxn];
int num_nodes, num_edges;

void bfs(){                   // 预处理, 反向 BFS 构造 d 数组
      memset(visited, 0, sizeof(visited));
      queue<int> q;
      q.push(sink);
      visited[sink] = true;
      d[sink] = 0;
      while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i = 0; i < g[u].size(); i++){
                  Edge& e = edges[g[u][i] ^ 1];
                  int v = e.from;
                  if(!visited[v] && e.capacity > e.flow){
                        visited[v] = true;
                        d[v] = d[u] + 1;
                        q.push(v);
                  }
            }
      }
}
int augment(){                                        // 增广
      int u = sink, df = INF;
      // 从汇点到源点通过 p 追踪增广路径, df 为一路上最小的残量
      while(u != source){
            Edge& e = edges[p[u]];
            df = min(df, e.capacity - e.flow);
            u = e.from;
      }
      u = sink;
      // 从汇点到源点更新流量
      while(u != source){
            Edge& e = edges[p[u]];
            e.flow += df;
            edges[p[u]^1].flow -= df;
            u = e.from;
      }
      return df;
}
int max_flow(){
      int flow = 0;
      bfs();
      memset(num, 0, sizeof(num));
      for(int i = 0; i < num_nodes; i++) num[d[i]] ++; // 这个地方,针对的是点从0開始编号的情况
      int u = source;
      memset(cur, 0, sizeof(cur));
      while(d[source] < num_nodes){
            if(u == sink){
                  flow += augment();
                  u = source;
            }
            bool advanced = false;
            for(int i = cur[u]; i < g[u].size(); i++){
                  Edge& e = edges[g[u][i]];
                  if(e.capacity > e.flow && d[u] == d[e.to] + 1){
                        advanced = true;
                        p[e.to] = g[u][i];
                        cur[u] = i;
                        u = e.to;
                        break;
                  }
            }
            if(!advanced){    //retreat
                  int m = num_nodes - 1;
                  for(int i = 0; i < g[u].size(); i++){
                        Edge& e = edges[g[u][i]];
                        if(e.capacity > e.flow) m = min(m, d[e.to]);
                  }
                  if(--num[d[u]] == 0) break;                    // gap 优化
                  num[d[u] = m+1] ++;
                  cur[u] = 0;
                  if(u != source){
                        u = edges[p[u]].from;
                  }
            }
      }
      return flow;
}
//------------------------我是分界线,上面是模板--------------------------
int np, nc, n, m;

void solve(){
      graph_init();
      int u, v, w;
      char ch;
      for(int i = 1; i <= m; i++){
            while(scanf("%c", &ch)){
                  if(ch == '(') break;
            }
            scanf("%d,%d%c%d",&u,&v,&ch,&w);
            add_Edge(u, v, w);
      }
      for(int i = 1; i <= np; i++){
            while(scanf("%c", &ch)){
                  if(ch == '(') break;
            }
            scanf("%d%c%d",&u, &ch, &w);
            add_Edge(n, u, w);
      }
      for(int i = 1; i <= nc; i++){
            while(scanf("%c", &ch)){
                  if(ch == '(') break;
            }
            scanf("%d%c%d",&v, &ch, &w);
            add_Edge(v, n+1, w);
      }

      num_nodes = n+2;
      source = n; sink = n+1;

      int ans = max_flow();
      printf("%d
",ans);
}
int main(){
      while(scanf("%d%d%d%d",&n,&np, &nc, &m) != EOF){
            solve();
      }
      return 0;
}


最终自己写了一个还不错的最大流啦....窝原来用的那个模板我囧的非常好了啊!

可是我干囧大家好像都再说Dinic是好。又有人在说ISAP好像更棒啊!

最终我如今两个都敲一下就好啦~~

ISAP跟DINIC还是有非常多相似的。


原文地址:https://www.cnblogs.com/jzssuanfa/p/7214224.html