分治最小割 学习总结
生活随笔
收集整理的這篇文章主要介紹了
分治最小割 学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這是一種可以較快的求解任意兩點間最小割的算法
正常的暴力的話我們要枚舉點對,一共要做O(n^2)次網絡流
而我們注意到設某一個S->T最小割中兩個點x,y,滿足x在S集合且y在T集合中
設S->T的最小割為C,x->y的最小割為W
則一定有C>=W
若取得大于號,則x->y的最小割中一定有一個屬于S集合點現在屬于y集合或者一個屬于T集合的點現在屬于x集合
這樣我們就可以分治處理并每次更新答案
實際上這樣操作構成了一棵樹,我們稱之為最小割樹,其任意兩點的最小割等價于兩點在樹上路徑的最小邊權
注意每次更新的時候要更新S->T的所有點對,而不是分治的那部分
因為大小為n的集合分裂次數為n-1次,所以我們只需要做O(n)次網絡流即可求解
具體算法是這樣的:
1、我們在當前可選點集中任取S,T,做最小割
2、用當前最小割把所以滿足i在S集合中且j在T集合中的點對(i,j)更新答案(取min)
3、分治處理S集合和T集合
?
CQOI 不同的最小割
OwO 直接分治+最小割,會得到O(n)個割,然后去重一下即可
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #include<queue> #include<set> using namespace std;const int maxn=1010; const int oo=0x7fffffff; int n,m,u,v,w,S,T,ans; int h[maxn],cnt=1,tim; int a[maxn],t1[maxn],t2[maxn]; int vis[maxn],check[maxn]; struct edge{int to,next,w; }G[50010]; set<int>V; queue<int>Q;void add(int x,int y,int z){++cnt;G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt; } void read(int &num){num=0;char ch=getchar();while(ch<'!')ch=getchar();while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } bool BFS(){memset(vis,-1,sizeof(vis));Q.push(S);vis[S]=0;while(!Q.empty()){int u=Q.front();Q.pop();for(int i=h[u];i;i=G[i].next){int v=G[i].to;if(vis[v]==-1&&G[i].w>0){vis[v]=vis[u]+1;Q.push(v);}}}return vis[T]!=-1; } int DFS(int x,int f){if(x==T||f==0)return f;int w,used=0;for(int i=h[x];i;i=G[i].next){if(vis[G[i].to]==vis[x]+1){w=f-used;w=DFS(G[i].to,min(w,G[i].w));G[i].w-=w;G[i^1].w+=w;used+=w;if(used==f)return used;}}if(!used)vis[x]=-1;return used; } void Get_Graph(){for(int i=2;i<=cnt;i+=2)G[i].w=G[i^1].w=(G[i].w+G[i^1].w)>>1;} void dinic(){ans=0;Get_Graph();while(BFS())ans+=DFS(S,oo); } void DFS(int u){if(check[u]==tim)return;check[u]=tim;for(int i=h[u];i;i=G[i].next){int v=G[i].to;if(G[i].w>0)DFS(v);}return; } void Get_ans(int L,int R){if(L==R)return;S=a[L];T=a[R];dinic();V.insert(ans);++tim;DFS(S);int l1=0,l2=0;for(int i=L;i<=R;++i){if(check[a[i]]==tim)t1[++l1]=a[i];else t2[++l2]=a[i];}for(int i=1;i<=l1;++i)a[L+i-1]=t1[i];for(int i=1;i<=l2;++i)a[L+l1+i-1]=t2[i];Get_ans(L,L+l1-1);Get_ans(L+l1,R); }int main(){read(n);read(m);for(int i=1;i<=n;++i)a[i]=i;for(int i=1;i<=m;++i){read(u);read(v);read(w);add(u,v,w);add(v,u,w);}Get_ans(1,n);ans=V.size();printf("%d\n",ans);return 0; }ZJOi 最小割
求出任意兩點間最小割,然后就隨意做了OwO
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #include<queue> using namespace std;const int maxn=210; const int oo=0x7fffffff; int t,n,m,q,x,S,T,ans; int u,v,w; int h[maxn],cnt=1; int fa[maxn]; struct edge{int to,next,w; }G[100010]; int a[maxn],t1[maxn],t2[maxn]; int vis[maxn],check[maxn],tim; int Ans[maxn][maxn]; queue<int>Q; void read(int &num){num=0;char ch=getchar();while(ch<'!')ch=getchar();while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } void add(int x,int y,int z){++cnt;G[cnt].to=y;G[cnt].next=h[x];G[cnt].w=z;h[x]=cnt; } bool BFS(){memset(vis,-1,sizeof(vis));vis[S]=0;Q.push(S);while(!Q.empty()){int u=Q.front();Q.pop();for(int i=h[u];i;i=G[i].next){int v=G[i].to;if(vis[v]==-1&&G[i].w>0){vis[v]=vis[u]+1;Q.push(v);}}}return vis[T]!=-1; } int DFS(int x,int f){if(x==T||f==0)return f;int w,used=0;for(int i=h[x];i;i=G[i].next){if(vis[G[i].to]==vis[x]+1){w=f-used;w=DFS(G[i].to,min(w,G[i].w));G[i].w-=w;G[i^1].w+=w;used+=w;if(used==f)return used;}}if(!used)vis[x]=-1;return used; } void DFS(int u){if(check[u]==tim)return;check[u]=tim;for(int i=h[u];i;i=G[i].next){int v=G[i].to;if(G[i].w>0)DFS(v);} } void Get_Graph(){for(int i=2;i<=cnt;i+=2)G[i].w=G[i^1].w=(G[i].w+G[i^1].w)>>1;} void dinic(){ans=0;Get_Graph();while(BFS())ans+=DFS(S,oo); } void Get_ans(int L,int R){if(L==R)return;S=a[L];T=a[R];dinic();tim++;DFS(S);int l1=0,l2=0;for(int i=L;i<=R;++i){if(check[a[i]]==tim)t1[++l1]=a[i];else t2[++l2]=a[i];}for(int i=1;i<=l1;++i)a[L+i-1]=t1[i];for(int i=1;i<=l2;++i)a[L+l1+i-1]=t2[i];for(int i=1;i<=n;++i){if(check[i]==tim){for(int j=1;j<=n;++j){if(check[j]!=tim){int u=i,v=j;if(u>v)swap(u,v);Ans[u][v]=min(Ans[u][v],ans);}}}}Get_ans(L,L+l1-1);Get_ans(L+l1,R); }int main(){scanf("%d",&t);while(t--){read(n);read(m);memset(h,0,sizeof(h));cnt=1;for(int i=1;i<=m;++i){read(u);read(v);read(w);add(u,v,w);add(v,u,w);}for(int i=1;i<=n;++i)a[i]=i;memset(Ans,0x3f,sizeof(Ans));Get_ans(1,n);read(q);while(q--){read(x);ans=0;for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)if(Ans[i][j]<=x)ans++;printf("%d\n",ans);}printf("\n");}return 0; }
轉載于:https://www.cnblogs.com/joyouth/p/5648678.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的分治最小割 学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdoj1176【DP】
- 下一篇: 使用Windbg调试StackOverf