日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最小费用最大流-SPFA-多路增广

發布時間:2024/4/11 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最小费用最大流-SPFA-多路增广 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

在最近的模擬賽當中,我碰到了一題二分圖最大權匹配的題,建圖比較簡單,因為是IOI賽制,所以可以爆OJ,然后呢,打了一發普通的spfa費用流,跑的很慢誒,只拿了70分,都有人AC了呢。那天的講題,好像說寫KM(二分圖最大權完美匹配的一種算法)就能過,但是呢,新的東西學還是需要一段時間的,但要訂正的話,emm,還是學一學優化的spfa費用流吧,即多路增廣一下,事實證明這是能過的。

算法介紹

多路增廣非常類似于dinic,然后我不會啊,然后就向高屆的大佬請教,大致的算法過程如下
對整一幅圖做一遍spfa(這個和一般spfa費用流相似),若匯點的距離為INF(意味著不能增廣),那么退出,否則做如下操作
每一次都用dfs進行一次增廣,若某一次增廣的流量為0,那么spfa一遍重新做
dfs是多路增廣與一般增廣的最大不同之處,每到一個點u,它要去擴展所有的點v滿足dis[u]+vau(邊權)==dis[v]
當然,需要使用當前弧優化才能保證復雜度

應用

相對于一般的spfa費用流,多路增廣尤其適用于邊流量特別小的圖(這些圖一次spfa如果只擴展一條邊那么效率將會變得很低下)

實現代碼

#include<cstdio> #include<cctype> #include<cmath> #include<algorithm> #include<cstring> namespace fast_IO {const int IN_LEN=10000000,OUT_LEN=10000000;char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf;char *lastin=ibuf+IN_LEN;const char *lastout=ibuf+OUT_LEN-1;inline char getchar_(){if(ih==lastin)lastin=ibuf+fread(ibuf,1,IN_LEN,stdin),ih=ibuf;return (*ih++);}inline void putchar_(const char x){if(ih==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);} } using namespace fast_IO; //#define getchar() getchar_() //#define putchar(x) putchar_((x)) typedef long long LL; #define rg register template <typename T> inline T max(const T a,const T b){return a>b?a:b;} template <typename T> inline T min(const T a,const T b){return a<b?a:b;} template <typename T> inline T abs(const T a){return a>0?a:-a;} template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;} template <typename T> inline T gcd(const T a,const T b){if(a%b==0)return b;return gcd(b,a%b);} template <typename T> inline T square(const T x){return x*x;}; template <typename T> inline void read(T&x) {char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x; } template <typename T> void printe(const T x) {if(x>=10)printe(x/10);putchar(x%10+'0'); } template <typename T> inline void print(const T x) {if(x<0)putchar('-'),printe(-x);else printe(x); } const int maxn=5002,maxm=100003; int N,M,S,T,maxflow,mincost; int head[maxn],cur[maxn],nxt[maxm],tow[maxm],vau[maxm],cost[maxm],tmp=1; inline void addb(const int u,const int v,const int w,const int f) {tmp++;nxt[tmp]=head[u];head[u]=tmp;tow[tmp]=v;vau[tmp]=w;cost[tmp]=f; } int dis[maxn],fr[maxn]; int Q[maxn],l,r; bool Hash[maxn]; inline int spfa() {memset(dis,0x7f,sizeof(dis));dis[S]=0;Hash[S]=1;l=r=0;Q[++r]=S;while(l!=r){l++;if(l==maxn)l=1;const int u=Q[l];for(rg int i=head[u];i;i=nxt[i]){const int v=tow[i];if(vau[i]&&dis[u]+cost[i]<dis[v]){dis[v]=dis[u]+cost[i];fr[v]=i;if(!Hash[v]){Hash[v]=1;r++;if(r==maxn)r=1;Q[r]=v;}}}Hash[u]=0;}return dis[T]; } int dfs(const int u,const int f) {if(f==0||u==T)return f;rg int sum=0;Hash[u]=1;for(rg int i=cur[u];i;i=nxt[i]){cur[u]=i;const int v=tow[i];if(dis[v]!=dis[u]+cost[i]||vau[i]==0)continue;if(!Hash[v]){const int ans=dfs(v,min(f-sum,vau[i]));sum+=ans,vau[i]-=ans,vau[i^1]+=ans;mincost+=cost[i]*ans;}} // cur[u]=head[u];Hash[u]=0;return sum; } inline void flow() {while(spfa()!=0x7f7f7f7f){for(rg int i=1;i<=N;i++)cur[i]=head[i];while(1){const int x=dfs(S,0x7f7f7f7f);if(x==0)break;maxflow+=x;if(mincost>=0x7f7f7f3e)return;}} } int main() {read(N),read(M),read(S),read(T);for(rg int i=1;i<=M;i++){int u,v,w,f;read(u),read(v),read(w),read(f);addb(u,v,w,f),addb(v,u,0,-f);}flow();print(maxflow),putchar(' '),print(mincost);return flush(),0; }

注意事項

使用多路增廣網絡流使用于一些有性質的圖會有很好的效果,但如果只是一般的圖的話那么效果就不是那么明顯啦(可能是我寫的常數比較大吧),所以呢,學多路增廣之后,對于普通spfa費用流的熟練掌握還是挺重要的

總結

以上是生活随笔為你收集整理的最小费用最大流-SPFA-多路增广的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。