[最小割树] Bzoj P2229 最小割

题目描述

小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: ”对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。

对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割“

现给定一张无向图,小白有若干个形如”图中有多少对点它们的最小割的容量不超过x呢“的疑问,小蓝虽然很想回答这些问题,但小蓝最近忙着挖木块,于是作为仍然是小蓝的好友,你又有任务了。

 

题解

  • 与上题差不多,把最小割树建出来后,暴力统计就好了

代码

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <queue>
 6 #define inf 0x3f3f3f3f
 7 #define N 160
 8 using namespace std;
 9 int s,t,cnt=1,n,m,q,T,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     for (scanf("%d",&T);T;T--)
70     {
71         scanf("%d%d",&n,&m),cnt=1; 
72         for (int i=1;i<=n;i++) a[i]=i;
73         memset(ans,inf,sizeof(ans)),memset(head,0,sizeof(head));
74         for (int i=1,x,y,z;i<=m;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z);
75         solve(1,n),scanf("%d",&q);
76         for (int i=1;i<=q;i++)
77         {
78             int x,tot=0; scanf("%d",&x);
79             for (int i=1;i<n;i++) for (int j=i+1;j<=n;j++) if (ans[i][j]<=x) tot++;
80             printf("%d\n",tot);
81         }
82         cout<<endl;
83     }
84 }

 

posted @ 2019-07-21 09:04  BEYang_Z  阅读(238)  评论(0编辑  收藏  举报