题目描述
给定一个nn个点mm条边的无向连通图,多次询问两点之间的最小割
两点间的最小割是这样定义的:原图的每条边有一个割断它的代价,你需要用最小的代价使得这两个点不连通
输入输出格式
输入格式:
第一行两个数n,mn,m
接下来mm行,每行33个数u,v,wu,v,w,表示有一条连接uu与vv的无向边,割断它的代价为ww
接下来这一行有一个整数QQ,表示询问次数
接下来QQ行,每行两个数u,vu,v,你需要求出uu与vv之间的最小割
注意:因为数据有误,给定图的真实点数应该是n+1n+1个,编号为00到nn
输出格式:
输出共QQ行,每行一个整数对应询问的答案
输入输出样例
说明
nleq 500,quad mleq 1500,quad Qleq 10^5,quad 0leq wleq 10^4n≤500,m≤1500,Q≤105,0≤w≤104
题解
-
一开始把所有点放进一个集合里面
-
先从集合中随意取出两个点作为源汇,在整个图中跑一遍最大流,就得到了这两个点的最小割
-
并把所有点分为了s集和t集,那么就更新s集到t集的答案,并把s集和t集往下递归
-
以此类推,到最后即可得到所有点对的最小割
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #define inf 0x3f3f3f3f 7 #define N 510 8 using namespace std; 9 int s,t,cnt=1,n,m,q,dis[N],head[N],a[N],tmp[N],ans[N][N],mark[N]; 10 struct edge{int to,c,from;}e[N*200]; 11 queue <int> Q; 12 void insert(int u,int v,int c) 13 { 14 e[++cnt].to=v,e[cnt].c=c,e[cnt].from=head[u],head[u]=cnt; 15 e[++cnt].to=u,e[cnt].c=c,e[cnt].from=head[v],head[v]=cnt; 16 } 17 bool bfs() 18 { 19 memset(dis,0,sizeof(dis)),dis[s]=2; 20 while (!Q.empty()) Q.pop(); Q.push(s); 21 while (!Q.empty()) 22 { 23 int u=Q.front(); Q.pop(); 24 for (int i=head[u];i;i=e[i].from) 25 if (e[i].c&&!dis[e[i].to]) 26 { 27 dis[e[i].to]=dis[u]+1; 28 if (e[i].to==t) return 1; 29 Q.push(e[i].to); 30 } 31 } 32 return 0; 33 } 34 int dfs(int x,int maxf) 35 { 36 if (x==t||!maxf) return maxf; 37 int ret=0; 38 for (int i=head[x];i;i=e[i].from) 39 if (e[i].c&&dis[e[i].to]==dis[x]+1) 40 { 41 int f=dfs(e[i].to,min(e[i].c,maxf-ret)); 42 e[i].c-=f,e[i^1].c+=f,ret+=f; 43 if (ret==maxf) break; 44 } 45 if (!ret) dis[x]=0; 46 return ret; 47 } 48 void dfs(int x) 49 { 50 mark[x]=1; 51 for (int i=head[x];i;i=e[i].from) if (e[i].c&&!mark[e[i].to]) dfs(e[i].to); 52 } 53 void solve(int l,int r) 54 { 55 if (l==r) return; 56 s=a[l],t=a[r]; 57 for (int i=2;i<=cnt;i+=2) e[i].c=e[i^1].c=(e[i].c+e[i^1].c)/2; 58 int flow=0; 59 while (bfs()) flow+=dfs(s,inf); 60 memset(mark,0,sizeof(mark)),dfs(s); 61 for (int i=1;i<=n;i++) if (mark[i]) for (int j=1;j<=n;j++) if (!mark[j]) ans[i][j]=ans[j][i]=min(ans[i][j],flow); 62 int i=l,j=r; 63 for (int k=l;k<=r;k++) if (mark[a[k]]) tmp[i++]=a[k]; else tmp[j--]=a[k]; 64 for (int k=l;k<=r;k++) a[k]=tmp[k]; 65 solve(l,i-1),solve(j+1,r); 66 } 67 int main() 68 { 69 scanf("%d%d",&n,&m); 70 for (int i=1;i<=n;i++) a[i]=i; 71 memset(ans,inf,sizeof(ans)); 72 for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z); 73 solve(1,n),scanf("%d",&q); 74 for (int i=1,x,y;i<=q;i++) scanf("%d%d",&x,&y),printf("%d ",ans[x][y]); 75 }