トピック:http://acm.hdu.edu.cn/showproblem.php?pid=6582
副作用のいくつかを削除すると最短辺の最小量が長くなり、削除要求の値ということです。
レンジエッジとポイントが1E4です。
短絡が最も長いということになっている場合、前最短通信にされなくなりました。元のパスがエッジを削除除去全ての最短の長さを、満たしている場合は最小のコストは、ブロックの通信に分割され、これらの辺の最小コストと同等です。
だから、新しいマップの両方の最短辺のすべての元の建設のための解決策を見つけるために、最小カットの新しいマップも望まれています。
ネットワークフロー:
参考ブログ:https://blog.csdn.net/zhouzi2018/article/details/81865934
https://blog.csdn.net/qq_41357771/article/details/79416899
ミーティングポイントに向かって導管を介して水供給源からの水、容量に対応する各管、多くの水が収束をシンクすることができ、最後の質問。
最も暴力的な思考では、各増強パスがソースポイントからシンクに流れることができる見つけるために、分水は、それぞれのケースを列挙中に実行可能な選択肢からの最大流量を選択します。
このプロセスでは、実際には、それはこれまでの質問の意味を満たすために調整されるまで相互調整の列挙の場合です。エッジの場合に放棄されるべき次のケースを選択することができます。
機会が経路を通って流れるように「戻る」にした場合、我々は動的変更になるためにパスを増強するプロセスように、冗長な誘惑を保存することができます。
Bからサイドに対抗するために、唯一の同じ重さ、それの方向とは反対側を追加する必要があります。
したがって、BFSは、幅広い抗エッジを構築するために並んで実行可能経路を見つけることとき。
ここ数相互に排他的OR正負の値。0と1に設定され、2及び3のセットです。
A
TのSからのパスを見つけ、最小容量が側流の重量を追加し、往路側がそれぞれ流れ、逆流プラス側が減算されます。このプロセスは、パスを増大させることなく、TにSまで繰り返されます。
Dinic
いくつかの時点で、EKは、次の図のように時間の無駄、次のようになります。
EK解決を使用すると、このパスを選択することができ1-2-3-4
そして、1-3-2-4を選択
値が大きい場合には、EKがタイムアウトします。
反复横跳的原因是因为EK在路径选择上没有优先和限制,因此先选择哪条路径做增广是随机的,同时由于反边的建立,图已经不是单纯的有向图,只要策略错误就会对效率有很大影响。
那么能否把图剥离成单纯的有向图?
给每个点一个深度,规定水只能从浅往深流,这样就得到了一个没有小环(仅有两点构成的环)的图。
但这样是否违背了可以‘反悔’的初衷呢?
每做完一次新图的增广,就重新分配一次深度。将图分为多层,上一层选择了水流从A到B的管道,那么下一层就提供水流可以从B到A的管道。由于每一层都要找完该层所有增广路再进入下一层,所以即使做出了耗时的策略,也只会在这一层做出一次,在其他路径被选择前,这个耗时的策略不会再被选择。同时满足了‘回流’和优化。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N = 100001; int s,t; int n,m; struct node{ int v; int next; }edge[N]; int head[N]; int cnt; int w[N*2];//正边和反边的权值 int d[N];//点的深度,每一层清 0 int q[N],qhead,qtail; int floor;//这一层的最大流 int ans;//原图的最大流 void add(int u,int v,int value) { edge[cnt].v=v; edge[cnt].next=head[u]; w[cnt]=value; head[u]=cnt; cnt++; } /* 分配深度 */ int bfs() { for(int i=1;i<=n;i++) d[i]=0; qhead=qtail=0; d[s]=1; q[++qtail]=s; while(qhead<qtail) { int u=q[++qhead]; for(int i=head[u];i>=0;i=edge[i].next) { if(w[i]>0&&d[edge[i].v]==0) { d[edge[i].v]=d[u]+1; q[++qtail]=edge[i].v; } } } /* 如果t未被更新深度,说明从s到t已无增广路 */ if(d[t]>0) return 1; else return 0; } /* 寻找增广路 */ /* u是当前所在的点,now是当前路径的流量 */ int dfs(int u,int now) { if(u==t) return now; for(int i=head[u];i>=0;i=edge[i].next) { if(w[i]>0&&d[edge[i].v]==d[u]+1) { /* 继续沿深度往下增广 */ int x=dfs(edge[i].v,min(now,w[i])); if(x) { /* 找到可行增广路,正边减流,反边增加 */ w[i]-=x; w[i^1]+=x; return x; } } } return 0; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) head[i]=-1; for(int i=1;i<=m;i++) { int u,v,value; scanf("%d%d%d",&u,&v,&value); /* 建正边和反边,反边剩余容量为0 */ add(u,v,value); add(v,u,0); } s=1;t=n; while(bfs()) { /* 遍历当前层的图的所有增广路 */ while(floor=dfs(s,0x7f7f7f)) { ans+=floor; floor=0; } } printf("%d",ans); }
原题:
#include<bits/stdc++.h> using namespace std; const int N = 10001; int T; int n,m; struct node{ int u,v,next,w; }e[N*2],E[N]; int head[N]; int HEAD[N]; int w[N*2]; int cnt,CNT; int s,t; struct NODE{ int id,dis; friend bool operator < (NODE n1,NODE n2) { return n1.dis<n2.dis; } }; int vis[N]; int dis[N]; long long f; int d[N]; long long ans; bool cmp(node e1,node e2) { return e1.w<e2.w; } void add(int u,int v,int c) { w[cnt]=c; e[cnt].v=v; e[cnt].next=head[u]; head[u]=cnt; cnt++; } void ADD(int u,int v,int c) { E[CNT].u=u; E[CNT].v=v; E[CNT].next=HEAD[u]; E[CNT].w=c; HEAD[u]=CNT; CNT++; } void read() { scanf("%d%d",&n,&m); s=1;t=n;ans=0; for(int i=1;i<=n;i++) { head[i]=HEAD[i]=dis[i]=-1; vis[i]=0; d[i]=0; } for(int i=1;i<=m;i++) { int x,y,c; scanf("%d%d%d",&x,&y,&c); ADD(x,y,c); } } void dij() { priority_queue<NODE> Q; NODE S; S.dis=0; S.id=s; Q.push(S); vis[s]=1; dis[s]=0; while(!Q.empty()) { NODE U=Q.top(); Q.pop(); int u=U.id; for(int i=HEAD[u];i!=-1;i=E[i].next) { if(dis[E[i].v]==-1||dis[E[i].v]>dis[u]+E[i].w) { dis[E[i].v]=dis[u]+E[i].w; if(!vis[E[i].v]) { vis[E[i].v]=1; NODE V; V.id=E[i].v; V.dis=dis[E[i].v]; Q.push(V); } } } } } void build() { for(int i=0;i<m;i++) { if(dis[E[i].v]==dis[E[i].u]+E[i].w) { add(E[i].v,E[i].u,0); add(E[i].u,E[i].v,E[i].w); } } } int bfs() { for(int i=1;i<=n;i++) d[i]=0; d[s]=1; queue<int> q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=e[i].next) { if(w[i]&&d[e[i].v]==0) { d[e[i].v]=d[u]+1; q.push(e[i].v); } } } return d[t]; } long long dfs(int u,int now) { if(u==t) return now; for(int i=head[u];i!=-1;i=e[i].next) { if(w[i]&&d[e[i].v]==d[u]+1) { int y=now; if(y==-1||y>w[i]) y=w[i]; int x=dfs(e[i].v,y); if(x) { w[i]-=x; w[i^1]+=x; return x; } } } return 0; } void dinic() { while(bfs()) { while(f=dfs(s,-1)) { ans+=f; f=0; } } } int main() { scanf("%d",&T); for(int i=1;i<=T;i++) { read(); dij(); build(); dinic(); printf("%lld",ans); } }