前面花了很长时间弄明白了压入-重标记的各种方法,结果号称是O(V3)的算法测demo的时候居然TLE了一个点,看了题解发现所有人都是用Dinic算法写的,但它的复杂度O(V2E)明显高于前者,具体是怎么回事我也不太清楚。。。但是Dinic算法相对来说要好理解多了。
经过证明(然而并不知道怎么证明),在残余网络中增广路中的最短路,一定是对答案贡献最大的(即对求解时间贡献最大)增广路。
算法显而易见了,每次找增广路之前先bfs一遍得出残余网络中源点到每个点的最短路径(每条边长度固定为1),得到一张“层次图”,根据层次图来找最优增广路(每个点只能向等级恰好比它多1的点流)
1 #include<iostream> 2 #include<iomanip> 3 #include<cstdio> 4 #include<map> 5 #include<queue> 6 #include<algorithm> 7 #include<ctime> 8 #include<cstring> 9 #include<cstdlib> 10 #include<climits> 11 #include<cmath> 12 #include<vector> 13 using namespace std; 14 #define rep(i,a,b) for(int i=a;i<=b;i++) 15 #define dep(i,a,b) for(int i=a;i>=b;i--) 16 inline int read(){ 17 int x=0;char ch=getchar(); 18 while(ch<'0'||ch>'9')ch=getchar(); 19 while(ch>='0'&&ch<='9'){ 20 x=x*10+ch-'0'; 21 ch=getchar(); 22 } 23 return x; 24 } 25 const int MAXN=100010,MAXM=1000010; 26 int to[MAXM],next[MAXM],value[MAXM]; 27 int level[MAXN],cnt=0,head[MAXN],s,t; 28 void _insert(int u,int v,int w){//链式前向星存图 29 to[cnt]=v; 30 value[cnt]=w; 31 next[cnt]=head[u]; 32 head[u]=cnt++; 33 to[cnt]=u; 34 value[cnt]=0; 35 next[cnt]=head[v]; 36 head[v]=cnt++; 37 } 38 bool bfs(){//构建层次图 39 memset(level,0,sizeof(level)); 40 level[s]=1;//level[i]表示每个点的层次,即源点到其的最短路径,初始化源点的层次为1(这个无所谓,只要层次递增即可) 41 queue<int>q; 42 q.push(s); 43 while(!q.empty()){ 44 int u=q.front(); 45 q.pop(); 46 for(int i=head[u];i!=-1;i=next[i]){ 47 if(!level[to[i]]&&value[i]){ 48 level[to[i]]=level[u]+1; 49 q.push(to[i]); 50 } 51 } 52 } 53 return level[t];//如果没有得出汇点的层次图,说明不存在增广路 54 } 55 int dfs(int u,int f){//u为当前节点,f为当前节点残余流量 56 if(!f||u==t)return f; 57 int rest=0; 58 for(int i=head[u];i!=-1;i=next[i]){ 59 if(value[i]&&level[u]+1==level[to[i]]){//只能向层次恰好多1的点流入 60 int p=dfs(to[i],min(f,value[i]));//深搜寻找瓶颈 61 rest+=p; 62 f-=p; 63 value[i]-=p; 64 value[i^1]+=p; 65 } 66 } 67 return rest; 68 } 69 int main(){ 70 int n=read(),m=read(); 71 s=read();t=read(); 72 memset(head,-1,sizeof(head)); 73 rep(i,1,m){ 74 int u=read(),v=read(),w=read(); 75 _insert(u,v,w); 76 } 77 int ans=0; 78 while(bfs())ans+=dfs(s,INT_MAX); 79 cout<<ans<<endl; 80 return 0; 81 }