BZOJ 2229: [Zjoi2011]最小割 最小割树 / 分治最小割

来源:互联网 发布:算法设计与分析课件 编辑:程序博客网 时间:2024/06/06 05:30

2229: [Zjoi2011]最小割

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 2217  Solved: 782
[Submit][Status][Discuss]

Description

小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。 对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割” 现给定一张无向图,小白有若干个形如“图中有多少对点它们的最小割的容量不超过x呢”的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。

Input

输入文件第一行有且只有一个正整数T,表示测试数据的组数。 对于每组测试数据, 第一行包含两个整数n,m,表示图的点数和边数。 下面m行,每行3个正整数u,v,c(1<=u,v<=n,0<=c<=106),表示有一条权为c的无向边(u,v) 接下来一行,包含一个整数q,表示询问的个数 下面q行,每行一个整数x,其含义同题目描述。

Output

对于每组测试数据,输出应包括q行,第i行表示第i个问题的答案。对于点对(p,q)和(q,p),只统计一次(见样例)。

两组测试数据之间用空行隔开。

Sample Input

1
5 0
1
0

Sample Output

10
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边


最小割树/分治最小割讲解传送门

分治法寻找n-1个最小割

对于当前点集V,任选两点为S.T做最小割

然后找出与S相连的所有点和与T相连的所有点构成S集与T集

更新S集与T集的最小割

然后递归处理两个集合


#include<cmath>#include<ctime>#include<cstdio>#include<cstring>#include<cstdlib>#include<complex>#include<iostream>#include<algorithm>#include<iomanip>#include<vector>#include<string>#include<bitset>#include<queue>#include<map>#include<set>using namespace std;typedef double db;typedef long long ll;inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=10*x+ch-'0';ch=getchar();}return x*f;}inline void print(int x){if(x<0)putchar('-');if(x>=10)print(x/10);putchar(x%10+'0');}const int N=160,M=100100,inf=0X3f3f3f3f;int n,a[N],ecnt,last[N];int ans[N][N];bool vis[N];struct EDGE{int to,nt,val;}e[M];inline void add(int u,int v,int val){e[++ecnt]=(EDGE){v,last[u],val};last[u]=ecnt;}int d[N],q[N],S,T;bool bfs(){memset(d,0,sizeof(d));int head=0,tail=1;q[0]=S;d[S]=1;while(head!=tail){int u=q[head++];for(int i=last[u];i;i=e[i].nt)if(!d[e[i].to]&&e[i].val){d[e[i].to]=d[u]+1;q[tail++]=e[i].to;}}return d[T];}int dfs(int u,int lim){if(u==T||!lim)return lim;int res=0;for(int i=last[u],tmp;i;i=e[i].nt)if(d[e[i].to]==d[u]+1&&e[i].val){tmp=dfs(e[i].to,min(e[i].val,lim));lim-=tmp;res+=tmp;e[i].val-=tmp;e[i^1].val+=tmp;if(!lim)break;}if(!res)d[u]=-1;return res;}void dfs(int u){vis[u]=1;for(int i=last[u];i;i=e[i].nt)if(e[i].val&&!vis[e[i].to])dfs(e[i].to);}void restore(){for(int i=2;i<=ecnt;i+=2)e[i].val=e[i^1].val=(e[i^1].val+e[i].val)>>1;}int tmp[N];void solve(int l,int r){if(l==r)return ;restore();S=a[l];T=a[r];int mf=0;while(bfs())mf+=dfs(S,inf);memset(vis,0,sizeof(vis));dfs(S);for(int i=1;i<=n;++i)if(vis[i])for(int j=1;j<=n;++j)if(!vis[j])ans[i][j]=ans[j][i]=min(ans[i][j],mf);int L=l,R=r;for(int i=l;i<=r;++i)if(vis[a[i]])tmp[L++]=a[i];else tmp[R--]=a[i];for(int i=l;i<=r;++i)a[i]=tmp[i];solve(l,L-1);solve(R+1,r);}int main(){int T=read();while(T--){memset(ans,0X7f,sizeof(ans));memset(last,0,sizeof(last));n=read();int m=read();ecnt=1;for(int i=1;i<=n;++i)a[i]=i;for(int i=1,u,v,val;i<=m;++i){u=read();v=read();val=read();add(u,v,val);add(v,u,val);}solve(1,n);int Q=read();while(Q--){int lim=read(),tot=0;for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)if(ans[i][j]<=lim)tot++;print(tot);puts("");}puts("");}return 0;}/*15 01010*/


原创粉丝点击