题目描述

学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割。
而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了。我们可以把视野放宽,考虑有N个点的无向连通图中所有点对的最小割的容量,共能得到N(N−1)2个数值。
这些数值中互不相同的有多少个呢?这似乎是个有趣的问题。

输入

输入文件第一行包含两个数N,M,表示点数和边数。接下来M行,每行三个数u,v,w,表示点u和点v(从1开始标号)之间有条边权值是w。
1<=N<=850 1<=M<=8500 1<=W<=100000

输出

输出文件第一行为一个整数,表示个数。

样例输入

4 4
1 2 3
1 3 6
2 4 5
3 4 4

样例输出

3


题解

分治+最小割,同 bzoj2229

最后统计答案时把两点最小割取出来,去个重,求一下个数即可。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define N 860
#define M 17010
using namespace std;
queue<int> q;
int n , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N] , a[N] , tmp[N] , ans[N][N] , v[1000000] , 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 m , i , j , x , y , z , ret = 0;
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;
memset(ans , 0x7f , sizeof(ans)) , 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);
v[0] = -1 << 30;
for(i = 1 ; i <= tot ; i ++ )
if(v[i] != v[i - 1])
ret ++ ;
printf("%d\n" , ret);
return 0;
}

【bzoj4519】[Cqoi2016]不同的最小割 分治+最小割的更多相关文章

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

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

  2. bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)

    2229: [Zjoi2011]最小割 题目:传送门 题解: 一道非常好的题目啊!!! 蒟蒻的想法:暴力枚举点对跑最小割记录...绝对爆炸啊.... 开始怀疑是不是题目骗人...难道根本不用网络流?? ...

  3. BZOJ 2229 / Luogu P3329 [ZJOI2011]最小割 (分治最小割板题)

    题面 求所有点对的最小割中<=c的数量 分析 分治最小割板题 首先,注意这样一个事实:如果(X,Y)是某个s1-t1最小割,(Z,W)是某个s2-t2最小割,那么X∩Z.X∩W.Y∩Z.Y∩W这 ...

  4. 【BZOJ-4519】不同的最小割 最小割树(分治+最小割)

    4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 393  Solved: 239[Submit][Stat ...

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

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

  6. [bzoj4519][Cqoi2016]不同的最小割_网络流_最小割_最小割树

    不同的最小割 bzoj-4519 Cqoi-2016 题目大意:题目链接. 注释:略. 想法: 我们发现这和最小割那题比较像. 我们依然通过那个题说的办法一样,构建最小割树即可. 接下来就是随便怎么处 ...

  7. BZOJ4519——[cqoi2016]不同的最小割

    0.题意:求两点之间的最小割的不同的总量 1.分析:裸的分治+最小割,也叫最小割树或GH树,最后用set搞一下就好 #include <set> #include <queue> ...

  8. BZOJ4519: [Cqoi2016]不同的最小割

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

  9. ZJOI 最小割 CQOI 不同的最小割 (最小割分治)

    题目1 ZJOI 最小割 题目大意: 求一个无向带权图两点间的最小割,询问小于等于c的点对有多少. 算法讨论: 最小割 分治 代码: #include <cstdlib> #include ...

随机推荐

  1. SIT&UAT

  2. MongoDB数据清理命令

    #启动mongo命令/data/liudi/mongodb/bin/mongo --port 27010 #显示数据库show dbs; #使用tps_live数据库use tps_live; #显示 ...

  3. sysbench0.5安装介绍

    sysbench是一个模块化的.跨平台.多线程基准测试工具,主要用于评估测试各种不同系统参数下的数据库负载情况,sysbench支持MySQL.PostgreSQL.Oracle数据库OLTP测试.它 ...

  4. VS2010中C++ 出现fatal error LNK1169: 找到一个或多个多重定义的符号

    一般是函数重定义造成的 例如定义了两个 sum(x,y)函数

  5. 快速生成导入亿级测试数据到sqlserver

    如果采用insert into 循环一条一条插入速度比较慢 可以先将数据插入临时表,然后在临时表数据量到达批量插入的行数时执行例如:目标表 (col1,col2,col3) --根据目标表结构复制一个 ...

  6. access处理重复创建表的方法。

    第一种,使用MSysObjects表查找表名为当前创建表的名字的内容,相当于普通查询,但是access数据库有一个安全问题,就是有时候一开始是没有权限去调这些系统表的,这时可以再2007的access ...

  7. 一条SQL语句在MySQL中是如何执行的

    概览 本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新是怎么完成的. 一.mysql架构分析 mysql主要分为Server层和存储 ...

  8. Navicat连接Oracle详细教程

    Navicat Premium算是比较好的一个可视化数据库管理工具了,短小精悍,一个工具解决三种数据库的连接问题,真正做到了集成管理,对MySQL,SQLServer而言,连接比较简单,就不赘述了,现 ...

  9. archlinux alsa安装,音量设置和音量信息保存

    1,使用前确认安装了alsa-utils sudo pacman -S alsa-utils2,运行alsamixer调试音量 alsamixer左右键选择调哪个,将Master和PCM按“m”解除静 ...

  10. golang 强制重新全部编译

    /home/用户名/.cache 删除缓存试试?? 修改的东西老失败 编译结果总不变 神奇了 go build -a    -x -v加一句-a 强制重新编译.