同zjoi的那倒最小割,跑最小割之后按S和T两个集合递归分治。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
#define M 20005
using namespace std;
int n,m,tot=1,sta,gol,cnt,fst[N],cur[N],pnt[M],len[M],nxt[M],d[N],h[N],num[N],fa[N],a[N],b[N],c[N];
bool vis[N];
void add(int x,int y,int z){
pnt[++tot]=y; len[tot]=z; nxt[tot]=fst[x]; fst[x]=tot;
}
void bfs(){
memset(num,0,sizeof(num));
memset(d,0x3f,sizeof(d)); d[gol]=0;
int head=0,tail=1; h[1]=gol;
while (head<tail){
int x=h[++head],p; num[d[x]]++;
for (p=fst[x]; p; p=nxt[p]) if (len[p^1]){
int y=pnt[p];
if (d[x]+1<d[y]){
d[y]=d[x]+1; h[++tail]=y;
}
}
}
}
int up(){
int i,tmp=1000000000;
for (i=gol; i!=sta; i=pnt[fa[i]^1]) tmp=min(tmp,len[fa[i]]);
for (i=gol; i!=sta; i=pnt[fa[i]^1]){
len[fa[i]]-=tmp; len[fa[i]^1]+=tmp;
}
return tmp;
}
int isap(){
int i;
for (i=2; i<=tot; i++){ len[i]=len[i^1]=(len[i]+len[i^1])>>1; }
bfs(); memcpy(cur,fst,sizeof(fst));
int x=sta,flow=0,p; bool flag;
while (d[x]<n){
if (x==gol){ flow+=up(); x=sta; }
flag=1;
for (p=cur[x]; p; p=nxt[p]) if (len[p]){
int y=pnt[p];
if (d[y]+1==d[x]){
fa[y]=cur[x]=p; x=y;
flag=0; break;
}
}
if (flag){
int mn=n-1; cur[x]=fst[x];
for (p=fst[x]; p; p=nxt[p])
if (len[p]) mn=min(mn,d[pnt[p]]);
num[d[x]]--; if (!num[d[x]]) break;
d[x]=mn+1; num[d[x]]++;
if (x!=sta) x=pnt[fa[x]^1];
}
}
return flow;
}
void dfs(int x){
vis[x]=1; int p;
for (p=fst[x]; p; p=nxt[p]) if (len[p]){
int y=pnt[p]; if (!vis[y]) dfs(y);
}
}
void solve(int l,int r){
if (l==r) return;
sta=a[l]; gol=a[r]; int flow=isap(),i;
c[++cnt]=flow;
memset(vis,0,sizeof(vis)); dfs(sta);
int x=l,y=r;
for (i=l; i<=r; i++)
if (vis[a[i]]) b[x++]=a[i]; else b[y--]=a[i];
for (i=l; i<=r; i++) a[i]=b[i];
if (l<x) solve(l,x-1); if (y<r) solve(y+1,r);
}
int main(){
scanf("%d%d",&n,&m); int i,x,y,z;
for (i=1; i<=m; i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z); add(y,x,z);
}
for (i=1; i<=n; i++) a[i]=i; solve(1,n);
sort(c+1,c+cnt+1); int ans=1;
for (i=2; i<=cnt; i++)
if (c[i]!=c[i-1]) ans++;
printf("%d\n",ans);
return 0;
}
by lych
2016.4.22