SW算法是一种求全局最小割的算法,复杂度为O(|V||E|+|V|^2log|V|)
算法类似于Prim算法:
每次从1节点开始,初始集合为{1}
每个节点的权值为他对于这个集合每个有边直接相连的顶点边权之和,设为dis[u]
每次找dis最大的点加入这个集合
设最后加的点为s,倒数第二加的点为t,那么dis[t]就是s-t的最小割,更新答案。
将t缩到s里面,再来一次(缩就是类似强连通分量那个缩点一样
如果用fib堆或pairing堆就可以O(1)修改,O(logn)每次找dis最大的点
其实这个题SW算法跑一次循环就能过...或者是用玄学O(n+m)贪心也可以(可能数据也不好造吧。。。
#include<bits/stdc++.h> #include <ext/pb_ds/priority_queue.hpp> #define maxn 3010 #define inf 1000000007 using namespace std; typedef pair<int,int> par; typedef __gnu_pbds :: priority_queue<par,less<par>,__gnu_pbds::pairing_heap_tag > Heap; struct edge{int r,nxt,w;}e[200100]; int n,m,f[maxn],vis[maxn],vis2[maxn],q[maxn],tp,nxt,dis[maxn],ans,head[maxn],esz; int _nxt[maxn],lst[maxn]; Heap st; Heap::point_iterator ps[maxn]; map<par,int>g; int find(int x){ return x==f[x]?x:f[x]=find(f[x]); } void addedge(int u,int v,int w){ e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;e[esz].w=w; e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;e[esz].w=w; } int solve(){ ans=inf; for(int i=1;i<=n;++i) f[i]=lst[i]=_nxt[i]=i; int lsn=n,s,t; for(int _n=n;_n>1;_n--){ for(int i=1;i<=n;++i) vis[i]=dis[i]=0,ps[i]=0; while(st.size())st.pop(); int xans=0,u=0,lastu=0,nxt=0; for(int r=1;r<=_n;++r){ int temp=-1; lastu=u; if(r>1){ u=st.top().second; st.pop(); } else u=1; vis[u]=1; bool flag=0; for(int j=u;;j=_nxt[j]){ for(int t=head[j],pre=0;t;t=e[t].nxt){ int v=find(e[t].r); xans++; if(u!=v&&!vis[v]){ if(!vis2[v])vis2[q[++tp]=v]=1; dis[v]+=e[t].w; } } if(j==lst[u])break; } for(int i=1;i<=tp;++i){ if(ps[q[i]]!=0) st.modify(ps[q[i]],par(dis[q[i]],q[i])); else ps[q[i]]=st.push(par(dis[q[i]],q[i])); vis2[q[i]]=0; } tp=0; } ans=min(ans,dis[u]); f[u]=lastu,_nxt[lst[lastu]]=u; lst[lastu]=lst[u]; } return ans; } int main(){ // freopen("in.txt","r",stdin); while(scanf("%d%d",&n,&m)==2){ g.clear(); for(int i=1;i<=n;++i)f[i]=i,head[i]=0;esz=0; for(int i=1,u,v,w;i<=m;++i){ scanf("%d%d%d",&u,&v,&w); if(u==v)continue; g[par(min(u,v),max(u,v))]+=w,f[find(u)]=find(v); } for(int i=1;i<=n;++i)if(find(i)!=find(1)){printf("0\n");goto nxt;} for(map<par,int>::iterator it=g.begin();it!=g.end();++it)addedge(it->first.first,it->first.second,it->second); printf("%d\n",solve()); nxt:; } }