同一个板子懒得写两篇了。。。
主要思路就是说n个点的无向图中最多有n-1个不同的最小割,更详细一点说,当我们对跑一次网络流,得到(S,T)两个点集,只需要分别在两个点集内部选点跑最大流即可。
也就是说如果我们从S,T中再任意各选一个点跑最大流,这个最大流一定会出现在我们用分治跑的最大流之中。
这样,我们求一个图中任意两个点的最小割的时间复杂度就从n^2次最大流变成了n次最大流。
还有一个坑点,2229不知道,4519如果是把一条无向边拆成两条有向边会被卡常数,有特殊的建图技巧。。。
UPD:ZJOJ今年DAY2 的讲课某神犇讲的就是这个东西,看完讲稿受益匪浅。。。知道了这东西居然有非递归写法还能把树建出来。。。但我不知道PPT讲稿方不方便放。。。(UOJ群里有大家自己去找吧233)
/**************************************************************
Problem: 4519
User: RicardoWang
Language: C++
Result: Accepted
Time:3764 ms
Memory:1692 kb
****************************************************************/
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define maxn 1005
#define maxm 10005
#define oo 999999999
struct edge
{
int u,v,c,f,next;
}e[maxm*2];
int edge_ct,head[maxn],n,m;
void add(int x,int y,int z)
{
e[++edge_ct]=(edge){x,y,z,0,head[x]}; head[x]=edge_ct;
}
void _read(int &x)
{
bool flag=false; char ch=getchar(); x=0;
while(ch<'0' || ch>'9'){if(ch=='-')flag=true; ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();} return;
}
void Init()
{
_read(n); _read(m);
int x,y,z;
edge_ct=0;
for(int i=1;i<=m;i++)
{
_read(x); _read(y); _read(z);
add(x,y,z); add(y,x,z);
}
return ;
}
int s,t,d[maxn],cur[maxn];
bool BFS()
{
for(int i=1;i<=n;i++)d[i]=0;
d[s]=1; queue<int>q; q.push(s);
int i,id;
while(!q.empty())
{
i=q.front(); q.pop();
for(id=head[i];id;id=e[id].next)
{
if(e[id].c<=e[id].f || d[e[id].v])continue;
d[e[id].v]=d[i]+1;
q.push(e[id].v);
}
}
return (d[t]>0);
}
int DFS(int now,int a)
{
if(now==t || a==0)return a;
int ans=0,f,j;
for(int &id=cur[now];id;id=e[id].next)
{
j=e[id].v;
if(d[j]==d[now]+1 && (f=DFS(j,min(a,e[id].c-e[id].f)))>0)
{
ans+=f;
e[id].f+=f;
e[id+ (id%2==0 ? -1 : 1)].f-=f;
a-=f;
if(!a)break;
}
}
return ans;
}
int Dinic(int x,int y)
{
s=x; t=y;
int ans=0;
while(BFS())
{
for(int i=1;i<=n;i++)cur[i]=head[i];
ans=ans+DFS(s,oo);
}
return ans;
}
int a[maxn],tmp[maxn];
bool v[maxn];
int ans[maxn],ans_cnt;
void dfs_2(int now)
{
v[now]=true;
for(int id=head[now];id;id=e[id].next)
{
if(v[e[id].v] || e[id].c<=e[id].f)continue;
dfs_2(e[id].v);
}
return ;
}
void work(int l,int r)
{
if(l>=r)return ;
int t;
for(int i=1;i<=edge_ct;i++)e[i].f=0;
t=Dinic(a[l],a[r]);
ans[++ans_cnt]=t;
for(int i=1;i<=n;i++)v[i]=false;
dfs_2(a[l]);
int L=l,R=r;
for(int i=l;i<=r;i++)
{
if(v[a[i]]){tmp[L]=a[i]; L++;}
else {tmp[R]=a[i]; R--;}
}
for(int i=l;i<=r;i++)
{
a[i]=tmp[i];
}
work(l,L-1); work(R+1,r);
return ;
}
int main()
{
//freopen("in.txt","r",stdin);
Init();
for(int i=1;i<=n;i++)a[i]=i;
work(1,n);
sort(ans+1,ans+1+ans_cnt);
ans_cnt=unique(ans+1,ans+1+ans_cnt)-ans-1;
printf("%d\n",ans_cnt);
return 0;
}