题目大意:一个无向图,求所有点对不同的最小割种类数
最小割最多有n-1个,这n-1个最小割构成一个最小割树
分治法寻找n-1个最小割。对于当前点集X,任选两点为ST做最小割,然后找出与S相连的所有点和与T相连的所有点构成S集与T集,更新S集与T集的最小割。然后递归处理两个集合。
最后将最小割排序,找出有多少不同最小割即可
#include#define inf 0x7ffffff using namespace std; inline int read(){ int s=0;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar()); for(;ch>='0'&&ch<='9';ch=getchar())s=s*10+ch-'0'; return s; } struct edge{ int to,next; int cap; }G[20010]; int tot=1,h[1000],S,T; void add(int x,int y,int z){ tot++;G[tot].to=y;G[tot].next=h[x];G[tot].cap=z;h[x]=tot; } int vis[1000],mark[1000]; int a[1000]; int n,m; set<int>s; bool bfs(){ memset(vis,0,sizeof(vis)); queue<int>Q;Q.push(S);vis[S]=1; 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]||G[i].cap<=0)continue; vis[v]=vis[u]+1; Q.push(v); } }return vis[T]; } int dfs(int u,int w){ if(u==T||w==0)return w; int flow=0; for(int i=h[u];i;i=G[i].next){ int v=G[i].to; if(vis[v]!=vis[u]+1||G[i].cap<=0)continue; if(int t=dfs(v,min(w,G[i].cap))){ G[i].cap-=t;G[i^1].cap+=t; flow+=t;w-=t; if(!w)break; } } if(!flow)vis[u]=0; return flow; } int dinic(){ int f=0; while(bfs())f+=dfs(S,inf); return f; } void dfs(int x){ mark[x]=1; for(int i=h[x];i;i=G[i].next) if(G[i].cap&&!mark[G[i].to]) dfs(G[i].to); } void clear(){ for(int i=2;i<=tot;i+=2) G[i].cap=G[i^1].cap=(G[i].cap+G[i^1].cap)/2; } int tmp[1000]; void solve(int l,int r){ if(l==r)return; clear(); S=a[l],T=a[r]; int t=dinic(); s.insert(t); memset(mark,0,sizeof(mark)); dfs(S); int L=l,R=r; for(int i=l;i<=r;++i) if(mark[a[i]])tmp[L++]=a[i]; else tmp[R--]=a[i]; for(int i=l;i<=r;++i)a[i]=tmp[i]; solve(l,L-1);solve(R+1,r); } int main(){ n=read();m=read(); for(int i=1;i<=m;++i){ int u=read(),v=read(),w=read(); add(u,v,w);add(v,u,w); } for(int i=1;i<=n;++i)a[i]=i; solve(1,n); printf("%d\n",s.size()); return 0; }