题目描述

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

输入

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

输出

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

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

样例输入

1
5 0
1
0

样例输出

10


题解

分治+网络流最小割

根据某些奇奇怪怪的定理,最小割最多只有n-1个。

那么我们只需要分治寻找这些最小割即可。

我们对于每次的点集,在其中任选两个为源点和汇点,求最小割,并更新任意两点之间最小割的答案。然后,把这些点集根据割开的S集合和T集合分成两个点集,再向下递归查询即可。

这样做能够保证每次的最小割都不同,就找到了n-1个最小割。

求最小割之后不需要再进行dfs,直接利用dis数组即可判断某点所在的集合。

最后把两点之间最小割拿出来排个序,再二分查找即可。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define N 200
#define M 20000
using namespace std;
queue<int> q;
int n , head[N] , to[M] , val[M] , next[M] , cnt , s , t , dis[N] , ans[N][N] , a[N] , tmp[N] , v[M] , tot;
void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = z , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
int x , i;
memset(dis , 0 , sizeof(dis));
while(!q.empty()) q.pop();
dis[s] = 1 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if(to[i] == t) return 1;
q.push(to[i]);
}
}
}
return 0;
}
int dinic(int x , int low)
{
if(x == t) return low;
int temp = low , i , k;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i] , min(temp , val[i]));
if(!k) dis[to[i]] = 0;
val[i] -= k , val[i ^ 1] += k;
if(!(temp -= k)) break;
}
}
return low - temp;
}
void solve(int l , int r)
{
if(l >= r) return;
int i , j , sum = 0 , p1 , p2;
for(i = 2 ; i <= cnt ; i += 2) val[i] = val[i ^ 1] = (val[i] + val[i ^ 1]) >> 1;
s = a[l] , t = a[r];
while(bfs()) sum += dinic(s , 1 << 30);
for(i = 1 ; i <= n ; i ++ )
if(dis[i])
for(j = 1 ; j <= n ; j ++ )
if(!dis[j])
ans[i][j] = ans[j][i] = min(ans[i][j] , sum);
for(p1 = i = l , p2 = r ; i <= r ; i ++ )
{
if(dis[a[i]]) tmp[p1 ++ ] = a[i];
else tmp[p2 -- ] = a[i];
}
for(i = l ; i <= r ; i ++ ) a[i] = tmp[i];
solve(l , p2) , solve(p1 , r);
}
int main()
{
int T;
scanf("%d" , &T);
while(T -- )
{
memset(head , 0 , sizeof(head)) , cnt = 1 , memset(ans , 0x7f , sizeof(ans)) , tot = 0;
int m , i , j , x , y , z , k;
scanf("%d%d" , &n , &m);
while(m -- ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z);
for(i = 1 ; i <= n ; i ++ ) a[i] = i;
solve(1 , n);
for(i = 1 ; i <= n ; i ++ )
for(j = i + 1 ; j <= n ; j ++ )
v[++tot] = ans[i][j];
sort(v + 1 , v + tot + 1);
scanf("%d" , &k);
while(k -- )
{
scanf("%d" , &x);
if(x >= v[tot]) printf("%d\n" , tot);
else printf("%d\n" , upper_bound(v + 1 , v + tot + 1 , x) - v - 1);
}
if(T) printf("\n");
}
return 0;
}

【bzoj2229】[Zjoi2011]最小割 分治+网络流最小割的更多相关文章

  1. [ZJOI2011]最小割 & [CQOI2016]不同的最小割 分治求最小割

    题面: [ZJOI2011]最小割 [CQOI2016]不同的最小割 题解: 其实这两道是同一道题.... 最小割是用的dinic,不同的最小割是用的isap 其实都是分治求最小割 简单讲讲思路吧 就 ...

  2. 【BZOJ2229】[ZJOI2011]最小割(网络流,最小割树)

    [BZOJ2229][ZJOI2011]最小割(网络流,最小割树) 题面 BZOJ 洛谷 题解 戳这里 那么实现过程就是任选两点跑最小割更新答案,然后把点集划分为和\(S\)联通以及与\(T\)联通. ...

  3. [bzoj2229][Zjoi2011]最小割_网络流_最小割树

    最小割 bzoj-2229 Zjoi-2011 题目大意:题目链接. 注释:略. 想法: 在这里给出最小割树的定义. 最小割树啊,就是这样一棵树.一个图的最小割树满足这棵树上任意两点之间的最小值就是原 ...

  4. 最小割分治(最小割树):BZOJ2229 && BZOJ4519

    定理:n个点的无向图的最小割最多n-1个. 可能从某种形式上形成了一棵树,不是很清楚. 最小割分治:先任选两个点求一边最小割,然后将两边分别递归,就能找到所有的最小割. 这两个题是一样的,直接搬din ...

  5. BZOJ2229: [Zjoi2011]最小割

    题解: 真是一道神题!!! 大家还是围观JZP的题解吧(网址找不到了...) 代码: #include<cstdio> #include<cstdlib> #include&l ...

  6. bzoj千题计划139:bzoj2229: [Zjoi2011]最小割

    http://www.lydsy.com/JudgeOnline/problem.php?id=2229 最小割树介绍:http://blog.csdn.net/jyxjyx27/article/de ...

  7. BZOJ2229[Zjoi2011]最小割——最小割树

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

  8. 【bzoj4519】[Cqoi2016]不同的最小割 分治+最小割

    题目描述 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将所有顶点处在不同 ...

  9. ACM/ICPC 之 最小割转网络流(POJ3469)

    重点:构图 //最小割转网络流 //邻接表+Dinic //Time:5797Ms Memory:6192K #include<iostream> #include<cstring& ...

随机推荐

  1. 自动完成文本框(AutoCompleteTextView与MultiAutoCompleteTextView)关联适配器

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  2. 利用js日期控件重构WEB功能

    开发需求:网页中的日期部门(注册页面和查询条件)都用js日期控件重写 页面一:更新员工页面 empUpdate.jsp 中增加 onfocus 事件 入职日期:<input id="h ...

  3. ubuntu 14.04 安装npm

    1. 安装 sudo apt install nodejs-legacy sudo apt install npm  

  4. Integer比较浅析

    //Integer 型比较假如是使用 == ,只能比较数值为-128~127数值; 在这个范围内使用的是自动装箱拆箱: //.intValue()使用这个需要确认属性不为null; //equals( ...

  5. lwz-过去一年的总结(15-16)

    今天2016年2月6日,还有1个半小时的时间,就要离开这个工作了9个月的地方,准备前往下个城市了.趁着这点时间,来给过去的一年做个即兴的总结吧. 2015年的2月份,在以前同学的提议和支持下,我重新学 ...

  6. HDOJ4550 卡片游戏 随便销毁内存的代价就是wa//string类的一些用法

    思路 标记最小的最后的位置  放在第一位 标记位置之前按left值小的左方大的右方 标记位置之后按顺序放在最后 不多说先贴上销毁内存的wa代码 销毁内存的wa代码 #include<cstdio ...

  7. MATLAB——解数独

    数独 数独是一种逻辑游戏,玩家需要根据9x9盘面的已知数字,推理出剩余所有空格的数字,并满足每一行.每一列和每个粗线宫(3x3)内均含1~9,不重复. MATLAB中有关函数 M = dlmread( ...

  8. UISearchBar的应用

    当你在seachBar中输入字母之前的时候,只是用鼠标选中searchBar的时候,如图 终端输出截图如下:(这个时候调用先shouldBeginEditing,之后调用didBeginEditing ...

  9. 单机简单搭建一个kafka集群(没有进行内核参数和JVM的调优)

    1.JDK安装 在我的部署单节点kafka的博客里有相关的方法.(https://www.cnblogs.com/ToBeExpert/p/9789486.html )zookeeper和kafka的 ...

  10. 【树形dp】7.14城市

    很典型的按照边考虑贡献的题. 题目描述 小A居住的城市可以认为由n个街区组成.街区从1到n依次标号街区与街区之间由街道相连,每个街区都可以通过若干条街道到达任意一个街区,共有n-1条街道.其中标号为i ...