题解:
两两之间的最小割等价于在Gomory–Hu 树上的最短边,同时告诉我们最小割最多只能有n-1种。 我们把Gomory–Hu 树建出来即可。
#include <bits/stdc++.h>
using namespace std;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
const int N=1e3+50,INF=0x3f3f3f;
vector <pii> edge[N];
int n,m,a[N],flow[N],vis[N],vs,tot;
namespace mf {
const int M=2e5+50;
int src,des,g[N],nt[M],vt[M],c[M],ec=1;
queue <int> q; int lev[N],cur[N];
inline void add(int x,int y,int cc) {nt[++ec]=g[x];g[x]=ec;vt[ec]=y;c[ec]=cc;}
inline void dfs(int x) {
vis[x]=vs;
for(int e=g[x];e;e=nt[e]) {if(c[e] && vis[vt[e]]!=vs) dfs(vt[e]);}
}
inline bool bfs() {
while(!q.empty()) q.pop();
memset(lev+1,0,sizeof(int)*n);
lev[src]=1; q.push(src);
while(!q.empty()) {
int u=q.front(); q.pop();
for(int e=g[u];e;e=nt[e]) {
if(!c[e] || lev[vt[e]]) continue;
lev[vt[e]]=lev[u]+1; q.push(vt[e]);
if(vt[e]==des) return true;
}
} return false;
}
inline int dinic(int x,int f) {
if(x==des) return f;
int rs=0;
for(int &e=cur[x];e;e=nt[e]) {
if(!c[e] || (lev[vt[e]]!=lev[x]+1)) continue;
int o=dinic(vt[e],min(f-rs,c[e]));
rs+=o; c[e]-=o; c[e^1]+=o;
if(rs==f) return rs;
} return lev[x]=0, rs;
}
inline void maxflow(int s,int t) {
memset(g,0,sizeof(g)); ec=1;
for(int i=1;i<=n;i++)
for(int e=edge[i].size()-1;e>=0;e--) {
int v=edge[i][e].first, w=edge[i][e].second;
if(v>i) add(i,v,w), add(v,i,w);
}
src=s; des=t; int rs=0;
while(bfs()) {
int t; memcpy(cur+1,g+1,sizeof(int)*n);
while((t=dinic(src,INF))) rs+=t, memcpy(cur+1,g+1,sizeof(int)*n);
}
flow[++tot]=rs;
}
}
inline void solve(int l,int r) {
if(l==r) return;
mf::maxflow(a[l],a[r]);
++vs; mf::dfs(a[l]);
static int tmp[N]; int ql=l,qr=r;
for(int i=l;i<=r;i++) if(vis[a[i]]==vs) tmp[ql++]=a[i]; else tmp[qr--]=a[i];
for(int i=l;i<=r;i++) a[i]=tmp[i];
solve(l,ql-1); solve(qr+1,r);
}
int main() {
n=rd(), m=rd();
for(int i=1;i<=m;i++) {
int x=rd(), y=rd(), w=rd();
edge[x].push_back(pii(y,w));
edge[y].push_back(pii(x,w));
}
for(int i=1;i<=n;i++) a[i]=i;
solve(1,n);
sort(flow+1,flow+tot+1); tot=unique(flow+1,flow+tot+1)-flow-1;
cout<<tot<<endl; return 0;
}