网络流模板

保存备用。

Dinic 网络流

/**
* @brief Dinic 网络流模板。
* @tparam Tp 权值的类型。
* @tparam sizn 点的数量。
* @tparam sizm 边的数量。
*/
template<typename Tp, size_t sizn, size_t sizm>
struct netflow
{
int cnt=1, s=sizn-3, t=sizn-2;
Tp val[sizm<<1], dis[sizn];
/**
* @brief 建一条有一定最大流量的有向边。
* @param u 有向边的起点。
* @param v 有向边的终点。
* @param w 边的最大流量。
*/
void link(int u, int v, Tp w)
{
to [++cnt]=v; val [cnt]=w;
nxt[ cnt ]=head[u]; head[ u ]=cnt;
to [++cnt]=u; val [cnt]=0;
nxt[ cnt ]=head[v]; head[ v ]=cnt;
}
const Tp inf=((Tp)INFINITY)>>1;
private:
int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1];
// 在残量网络中构造分层图
int bfs()
{
for(int i=1;i<sizn;i++) dis[i]=inf;
queue<int> q;
q.push(s);
dis[s]=0;
now[s]=head[s];
while (!q.empty())
{
int idx=q.front(); q.pop();
for(int i=head[idx];i;i=nxt[i])
{
int arr=to[i];
if(val[i]>0&&dis[arr]==inf)
{
q.push(arr);
now[arr]=head[arr];
dis[arr]=dis [idx]+1;
if(arr==t) return 1;
}
}
}
return 0;
}
// dfs 找增广路并处理
Tp dfs(int idx, Tp sum)
{
if(idx==t) return sum;
Tp k, res=0;
for(int i=now[idx];i&&sum;i=nxt[i])
{
now[idx]=i;
int arr=to[i];
if(val[i]>0&&(dis[arr]==dis[idx]+1))
{
k=dfs(arr, min(sum, val[i]));
if(k==0) dis[arr]=inf;
val[i]-=k; res+=k;
val[i^1]+=k; sum-=k;
}
}
return res;
}
public:
/**
* @brief Dinic求解最大流。
* @return 最大流大小。
* @warning 它不能在常数时间内给出结果。
*/
Tp maxflow()
{
Tp ans=0;
while (bfs()) ans+=dfs(s, inf);
return ans;
}
};

Primal-Dual 费用流

/**
* @brief Primal 费用流模板。
* @tparam Tp 权值的类型。
* @tparam sizn 点的数量。
* @tparam sizm 边的数量。
*/
template<typename Tp, size_t sizn, size_t sizm>
struct costflow
{
#define pb __gnu_pbds
typedef pb::priority_queue<pair<Tp, int>,
greater<pair<Tp, int> >,
pb::pairing_heap_tag> pairing_heap;
int cnt=1, s=sizn-2, t=sizn-3;
Tp delta=0, MXflow=0, MNcost=0;
/**
* @brief 建一条有一定最大流量的有向边。
* @param u 有向边的起点。
* @param v 有向边的终点。
* @param w 边的最大流量。
* @param f 边的费用。
*/
void link(int u, int v, Tp w, Tp f)
{
to [++cnt]=v; cap [cnt]=w;
nxt[ cnt ]=head[u]; head[ u ]=cnt;
cost[cnt ]=f; from[cnt]=u;
to [++cnt]=u; cap [cnt]=0;
nxt[ cnt ]=head[v]; head[ v ]=cnt;
cost[cnt ]=-f; from[cnt]=v;
}
private:
bitset<sizn> vis;
pairing_heap pq;
typename pairing_heap :: point_iterator it[sizn];
Tp val[sizm<<1], dis[sizn], flow[sizn], cost[sizm<<1], cap[sizm<<1];
int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1], from[sizm<<1];
bool SPFA()
{
queue<int> q;
memset(dis, 0x3f, sizeof dis);
vis.reset();
dis[t]=0; q.push(t);
vis[t]=1;
while (!q.empty())
{
int u=q.front(); q.pop();
vis[u]=0;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
Tp f=val[i^1], c=cap[i^1], len=cost[i^1];
if(f<c&&dis[v]>dis[u]+len)
{
dis[v]=dis[u]+len;
if(!vis[v]) vis[v]=1, q.push(v);
}
}
}
return dis[s]!=dis[0];
}
void reduce()
{
for(int i=2;i<=cnt;i++) cost[i]+=dis[to[i]]-dis[from[i]];
delta+=dis[s];
}
bool Dijkstra()
{
memset(dis, 0x3f, sizeof dis);
memset(it, 0, sizeof it);
dis[t] = 0;
it[t] = pq.push({dis[t], t});
while(!pq.empty())
{
int u = pq.top().second; pq.pop();
for(int j=head[u];j;j=nxt[j])
{
int v=to[j];
Tp f=val[j^1], c=cap[j^1], len=cost[j^1];
if(f<c&&dis[v]>dis[u]+len)
{
dis[v]=dis[u]+len;
if(it[v]==NULL) it[v]=pq.push({dis[v], v});
else pq.modify(it[v], {dis[v], v});
}
}
}
return dis[s] != dis[0];
}
// dfs 找增广路并处理
Tp dfs(int idx, Tp sum)
{
if(idx==t) return sum;
vis[idx]=1;
Tp k, ret=sum;
for(int i=head[idx];i&&sum;i=nxt[i])
{
int v=to[i];
Tp f=val[i], c=cap[i], len=cost[i];
if(!vis[v]&&f<c&&!len)
{
k=dfs(v, min(ret, c-f));
val[i]+=k;
val[i^1]-=k;
ret-=k;
}
}
return sum-ret;
}
void augment()
{
Tp curflow=0;
vis.reset();
while((curflow=dfs(s, dis[0])))
{
MXflow+=curflow;
MNcost+=curflow*delta;
vis.reset();
}
}
public:
/**
* @brief Primal Dual 求解最小费用最大流。
* @return 无。
* @warning 它不能在常数时间内给出结果。
*/
void PrimalDual()
{
if(!SPFA()) return;
reduce(); augment();
while(Dijkstra()) {reduce(); augment();}
}
};

最高标号预流推进

template<typename Tp, size_t sizn, size_t sizm>
struct HLPP
{
int cnt=1, s=sizn-5, t=sizn-4, n=0;
Tp val[sizm<<1], dis[sizn];
int head[sizn], to[sizm<<1], nxt[sizm<<1], now[sizm<<1];
void link(int u, int v, Tp w)
{
n=max({n, u, v});
to [++cnt]=v; val [cnt]=w;
nxt[ cnt ]=head[u]; head[ u ]=cnt;
to [++cnt]=u; val [cnt]=0;
nxt[ cnt ]=head[v]; head[ v ]=cnt;
}
const Tp inf=0x3f3f3f3f;
int hgt[sizn], gap[sizn], vis[sizn];
Tp excess[sizn];
queue<int> q;
bool init()
{
fill_n(hgt, sizn, inf);
hgt[t]=0;
q.emplace(t);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=nxt[i])
if(val[i^1]&&hgt[to[i]]-1>hgt[u])
q.emplace(to[i]),
hgt[to[i]]=hgt[u]+1;
}
return hgt[s]!=inf;
}
priority_queue<pair<int, int>> pq;
void push(int u)
{
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(!excess[u]) break;
if(!val[i]||hgt[v]!=hgt[u]-1) continue;
Tp flw=min(val[i], excess[u]);
val[i]-=flw, val[i^1]+=flw;
excess[u]-=flw;
excess[v]+=flw;
if(v!=s&&v!=t&&!vis[v])
vis[v]=1, pq.emplace(hgt[v], v);
}
}
void relabel(int u)
{
hgt[u]=inf;
for(int i=head[u];i;i=nxt[i])
if(val[i]&&hgt[to[i]]<hgt[u]-1)
hgt[u]=hgt[to[i]]+1;
}
Tp maxflow()
{
if(!init()) return 0;
hgt[s]=n;
for(int i=1;i<=n;i++)
if(hgt[i]!=inf) gap[hgt[i]]++;
for(int i=head[s];i;i=nxt[i])
{
int v=to[i];
if(!val[i]||hgt[v]==inf) continue;
Tp flw=val[i];
val[i]-=flw, val[i^1]+=flw;
excess[s]-=flw, excess[v]+=flw;
if(v!=s&&v!=t&&!vis[v])
vis[v]=1, pq.emplace(hgt[v], v);
}
while(!pq.empty())
{
int u=pq.top().second;
pq.pop();
vis[u]=0;
push(u);
if(!excess[u]) continue;
if(!--gap[hgt[u]])
for(int i=1;i<=n;i++)
if(i!=s&&i!=t&&hgt[i]>hgt[u]&&hgt[i]<n+1)
hgt[i]=n+1;
relabel(u);
++gap[hgt[u]];
vis[u]=1;
pq.emplace(hgt[u], u);
}
return excess[t];
}
};

本文作者:Jimmy-LEEE

本文链接:https://www.cnblogs.com/redacted-area/p/18064974

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起