网络流模板
保存备用。
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&∑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&∑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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步