同一个板子懒得写两篇了。。。
主要思路就是说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; }