题目大意:
求一张无向图中两两点之间不同的最小割的种数,n<=850,m<=8500;
解题思路:
即是要构造最小割树,统计不同边权的数量。
有一个结论:任意两点之间的最小割,不同的只有n-1个(然而不会证明……)
构造最小割树方法如下(分治+最小割):
1.集合中随便找两个点,求这两点的最小割
2.用求出的最小割更新s,t两个集合之间点的最小割(或者可以直接建边,那么最终两点之间的最小割就是两点之间路径的最小权值
3.对s,t两个集合递归处理
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=1005,M=20005,INF=1e9;
int n,m,ans,S,T,a[N],b[N],dis[N],tag[N];
int tot=1,cur[N],first[N],nxt[M],to[M],cap[M];
map<int,int>mp;queue<int>q;
void add(int x,int y,int z)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y,cap[tot]=z;
nxt[++tot]=first[y],first[y]=tot,to[tot]=x,cap[tot]=z;
}
bool bfs()
{
for(int i=1;i<=n;i++)dis[i]=-1,cur[i]=first[i];
while(!q.empty())q.pop();
dis[S]=0,q.push(S);
while(!q.empty())
{
int u=q.front();q.pop();
for(int e=first[u];e;e=nxt[e])
{
int v=to[e];
if(dis[v]==-1&&cap[e])
{
dis[v]=dis[u]+1;
if(v==T)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int u,int flow)
{
if(u==T)return flow;
int res=0;
for(int &e=cur[u];e;e=nxt[e])
{
int v=to[e];
if(dis[v]==dis[u]+1&&cap[e])
{
int det=dfs(v,min(cap[e],flow-res));
cap[e]-=det,cap[e^1]+=det;
res+=det;if(res==flow)break;
}
}
if(res<flow)dis[u]=-1;
return res;
}
void dfs(int u)
{
tag[u]=1;
for(int e=first[u];e;e=nxt[e])
if(!tag[to[e]]&&cap[e])dfs(to[e]);
}
void solve(int l,int r)
{
if(l==r)return;
for(int i=2;i<=tot;i++)cap[i]=cap[i^1]=(cap[i]+cap[i^1])/2;
S=a[l],T=a[r];int res=0;
while(bfs())res+=dfs(S,INF);
if(!mp[res])ans++,mp[res]=1;
for(int i=1;i<=n;i++)tag[i]=0;
dfs(S);
int t1=l-1,t2=r+1;
for(int i=l;i<=r;i++)
tag[a[i]]?b[++t1]=a[i]:b[--t2]=a[i];
for(int i=l;i<=r;i++)a[i]=b[i];
solve(l,t1),solve(t2,r);
}
int main()
{
//freopen("lx.in","r",stdin);
int x,y;
n=getint(),m=getint();
while(m--)x=getint(),y=getint(),add(x,y,getint());
for(int i=1;i<=n;i++)a[i]=i;
solve(1,n);
cout<<ans<<'\n';
}