bzoj2229 [Zjoi2011]最小割
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
5 0
1
0
Sample Output
10
【数据范围】
对于100%的数据 T<=10,n<=150,m<=3000,q<=30,x在32位有符号整数类型范围内。
图中两个点之间可能有多条边
正解:最小割树。
因为今天考试相关所以就学习了一下最小割树。
因为一个图任意两点间的最小割数不会超过$n-1$,很显然,我们可以构造出一棵树,使得任意两点间的最小割就是原图两点的最小割。
具体构建方法:先随便选两个点$s$和$t$,选好点以后跑最小割,然后我们通过割把图分成两个集合,再用分治的方法分别对两个集合跑最小割即可。
求出任意两点间的最小割以后暴力比较就行了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define N (210) 16 #define il inline 17 #define RG register 18 #define ll long long 19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 20 21 using namespace std; 22 23 struct edge{ int nt,to,flow,cap; }g[10010]; 24 25 int head[N],vis[N],tmp[N],id[N],d[N],q[N],ans[N][N],Q,n,m,num,cnt; 26 27 il int gi(){ 28 RG int x=0,q=1; RG char ch=getchar(); 29 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 30 if (ch=='-') q=-1,ch=getchar(); 31 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 32 return q*x; 33 } 34 35 il void insert(RG int from,RG int to,RG int cap){ 36 g[++num]=(edge){head[from],to,0,cap},head[from]=num; return; 37 } 38 39 il int bfs(RG int S,RG int T){ 40 memset(d,0,sizeof(d)); 41 RG int h=0,t=1; q[t]=S,d[S]=1; 42 while (h<t){ 43 RG int x=q[++h],v; 44 for (RG int i=head[x];i;i=g[i].nt){ 45 v=g[i].to; 46 if (!d[v] && g[i].cap>g[i].flow){ 47 d[v]=d[x]+1,q[++t]=v; 48 if (v==T) return 1; 49 } 50 } 51 } 52 return 0; 53 } 54 55 il int dfs(RG int x,RG int T,RG int a){ 56 if (x==T || !a) return a; RG int flow=0,f,v; 57 for (RG int i=head[x];i;i=g[i].nt){ 58 v=g[i].to; 59 if (d[v]==d[x]+1 && g[i].cap>g[i].flow){ 60 f=dfs(v,T,min(a,g[i].cap-g[i].flow)); 61 if (!f){ d[v]=-1; continue; } 62 g[i].flow+=f,g[i^1].flow-=f; 63 flow+=f,a-=f; if (!a) return flow; 64 } 65 } 66 return flow; 67 } 68 69 il int maxflow(RG int S,RG int T){ 70 RG int flow=0; 71 while (bfs(S,T)) flow+=dfs(S,T,inf); 72 return flow; 73 } 74 75 il void Dfs(RG int x){ 76 vis[x]=cnt; 77 for (RG int i=head[x];i;i=g[i].nt) 78 if (g[i].cap>g[i].flow && vis[g[i].to]!=cnt) Dfs(g[i].to); 79 return; 80 } 81 82 il void solve(RG int L,RG int R){ 83 if (L==R) return; 84 for (RG int i=2;i<=num;i+=2) g[i].flow=g[i^1].flow=0; 85 RG int flow=maxflow(id[L],id[R]); ++cnt,Dfs(id[L]); 86 for (RG int i=1;i<=n;++i){ 87 if (vis[i]!=cnt) continue; 88 for (RG int j=1;j<=n;++j) 89 if (vis[j]!=cnt) ans[i][j]=ans[j][i]=min(ans[i][j],flow); 90 } 91 RG int l=L,r=R; 92 for (RG int i=L;i<=R;++i) (vis[id[i]]==cnt)?tmp[l++]=id[i]:tmp[r--]=id[i]; 93 for (RG int i=L;i<=R;++i) id[i]=tmp[i]; 94 solve(L,l-1),solve(r+1,R); return; 95 } 96 97 il void work(){ 98 memset(head,0,sizeof(head)),num=1; 99 memset(ans,0x3f3f3f,sizeof(ans)),n=gi(),m=gi(); 100 for (RG int i=1;i<=n;++i) id[i]=i; 101 for (RG int i=1,u,v,w;i<=m;++i) 102 u=gi(),v=gi(),w=gi(),insert(u,v,w),insert(v,u,w); 103 solve(1,n),Q=gi(); 104 for (RG int i=1,c,res;i<=Q;++i){ 105 c=gi(),res=0; 106 for (RG int j=1;j<n;++j) 107 for (RG int k=j+1;k<=n;++k) if (ans[j][k]<=c) ++res; 108 printf("%d\n",res); 109 } 110 puts(""); return; 111 } 112 113 int main(){ 114 File("cut"); 115 RG int T=gi(); 116 while (T--) work(); 117 return 0; 118 }