正题
题目大意:https://www.luogu.com.cn/problem/P4123
题目大意
一张无向图,求所有点对之间有多少不同的最小割。
解题思路
考虑分治的做法,如果我们得知了(s,t)(s,t)(s,t)的最小割www,并且剩下的残量网络中连通点集SSS与sss连通,点集TTT与ttt连通。那么点集SSS到TTT的每个点对之间的最小割都是www。然后分治到两个点集去做即可。
这样下来最小割的期望次数是O(n)O(n)O(n)级别的,可以通过本题。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
const int N=900,inf=2147483647/3;
struct node{int to,next,w,ret;
}a[N*20];
int n,m,ls[N],tot=1;
int dep[N],p[N],ans;
map<int,int> mp;
queue<int> q;
void addl(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[tot].ret=w;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=w;a[tot].ret=w;return;
}
bool bfs(int s,int t){memset(dep,0,sizeof(dep));dep[s]=1;while(!q.empty())q.pop();q.push(s);while(!q.empty()){int x=q.front();q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dep[y]||!a[i].w)continue;dep[y]=dep[x]+1;if(y==t)return 1;q.push(y);}}return 0;
}
int dinic(int x,int flow,int t){int rest=0,k;if(x==t)return flow;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(dep[x]+1!=dep[y]||!a[i].w)continue;rest+=(k=dinic(y,min(flow-rest,a[i].w),t));a[i].w-=k;a[i^1].w+=k;if(flow==rest)return flow;}if(!rest)dep[x]=0;return rest;
}
bool cmp(int x,int y)
{return dep[x]<dep[y];}
void solve(int l,int r){if(l==r)return;int w=0; while(bfs(p[l],p[r]))w+=dinic(p[l],inf,p[r]);if(!mp.count(w))mp[w]=1,ans++;sort(p+l,p+1+r,cmp);int mid=l;for(int i=l;i<=r;i++)if(dep[p[i]]){mid=i;break;}for(int i=1;i<=tot;i++)a[i].w=a[i].ret;solve(l,mid-1);solve(mid,r);return;
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)p[i]=i;for(int i=1;i<=m;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);addl(x,y,w);}solve(1,n);printf("%d\n",ans);
}