Description

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

Input

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

Output

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

 

Sample Input

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

Sample Output

3
 
经典的分治最小割问题,有这样一个结论:最小割最多有n-1个,这n-1个最小割构成一个最小割树(可见2016国家队论文)
大意是每次任取一个源汇求出最小割,然后分治S割和T割的节点,时间复杂度为N*O(最小割)。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
if(head==tail) {
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
}
return *head++;
}
inline int read() {
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=910;
const int maxm=20010;
struct Dinic {
struct Edge {int from,to,flow;}edges[maxm];
int n,m,s,t,first[maxn],next[maxm];
int d[maxn],vis[maxn],cur[maxn];
void init(int n) {
this->n=n;m=0;
memset(first,-1,sizeof(first));
}
void AddEdge(int u,int v,int w) {
edges[m]=(Edge){u,v,w};next[m]=first[u];first[u]=m++;
edges[m]=(Edge){v,u,w};next[m]=first[v];first[v]=m++;
}
void reset() {rep(i,0,m-1) edges[i].flow=edges[i^1].flow=(edges[i].flow+edges[i^1].flow)>>1;}
int Q[maxn],clo;
int BFS() {
int l=1,r=0;Q[++r]=s;vis[s]=++clo;
while(l<=r) {
int x=Q[l++];cur[x]=first[x];
ren {
Edge& e=edges[i];
if(e.flow&&vis[e.to]!=clo) {
vis[e.to]=clo;
d[e.to]=d[x]+1;
Q[++r]=e.to;
}
}
}
return vis[t]==clo;
}
int DFS(int x,int a) {
if(x==t||!a) return a;
int flow=0,f;
for(int& i=cur[x];i!=-1;i=next[i]) {
Edge& e=edges[i];
if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.flow)))) {
e.flow-=f;edges[i^1].flow+=f;
flow+=f;a-=f;if(!a) break;
}
}
return flow;
}
int solve(int s,int t) {
this->s=s;this->t=t;int flow=0;
while(BFS()) flow+=DFS(s,1e9);
return flow;
}
}sol;
int cnt,A[maxn],tmp[maxn],ans[maxm];
void solve(int l,int r) {
if(l>=r) return;sol.reset();
ans[++cnt]=sol.solve(A[l],A[r]);
int L=l,R=r;
rep(i,l,r) {
if(sol.vis[A[i]]==sol.clo) tmp[L++]=A[i];
else tmp[R--]=A[i];
}
rep(i,l,r) A[i]=tmp[i];
solve(l,R);solve(L,r);
}
int main() {
int n=read(),m=read();sol.init(n);
rep(i,1,m) {
int a=read(),b=read(),c=read();
sol.AddEdge(a,b,c);
}
rep(i,1,n) A[i]=i;solve(1,n);
sort(ans+1,ans+cnt+1);
int res=1;
rep(i,2,cnt) if(ans[i]!=ans[i-1]) res++;
printf("%d\n",res);
return 0;
}

  

BZOJ4519: [Cqoi2016]不同的最小割的更多相关文章

  1. bzoj千题计划140:bzoj4519: [Cqoi2016]不同的最小割

    http://www.lydsy.com/JudgeOnline/problem.php?id=4519 最小割树 #include<queue> #include<cstdio&g ...

  2. bzoj4519: [Cqoi2016]不同的最小割(分治最小割)

    4519: [Cqoi2016]不同的最小割 题目:传送门 题解: 同BZOJ 2229 基本一样的题目啊,就最后用set记录一下就ok 代码: #include<cstdio> #inc ...

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

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

  4. BZOJ4519 CQOI2016不同的最小割(最小割+分治)

    最小割树:新建一个图,包含原图的所有点,初始没有边.任取两点跑最小割,给两点连上权值为最小割的边,之后对于两个割集分别做同样的操作.最后会形成一棵树,树上两点间路径的最小值即为两点最小割.证明一点都不 ...

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

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

  6. BZOJ4519[Cqoi2016]不同的最小割——最小割树+map

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

  7. bzoj4519: [Cqoi2016]不同的最小割(最小割树)

    传送门 好神仙……最小割树是个什么东西…… 其实我觉得干脆直接$O(n^2)$跑几个dinic算了…… 来说一下这个叫最小割树的神奇东西 我们先建一个$n$个点,没有边的无向图 在原图中任选两点$s, ...

  8. 【BZOJ4519】[Cqoi2016]不同的最小割 最小割树

    [BZOJ4519][Cqoi2016]不同的最小割 Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分 ...

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

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

随机推荐

  1. linux命令**50

    1.ls命令 命令格式: ls [选项] [目录名] 命令功能: 列出目标目录中所有的子目录和文件. 常用参数: -a,列出所有文件包括隐藏文件 -l,列出详细信息,文件大小一般以字节大小显示 -h, ...

  2. SQLAlchemy Core中的异常及事务处理样码

    这部门内容比较简单,立存. #coding=utf-8 from datetime import datetime from sqlalchemy import (MetaData, Table, C ...

  3. js 随机星星 document.createElement(); setAttribute()

    js 随机星星 document.createElement(); setAttribute() <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1. ...

  4. ThinkPHP3.2判断手机端访问并设置默认访问模块的方法

    ThinkPHP3.2判断是否为手机端访问并跳转到另一个模块的方法 目录结构 公共模块Common,Home模块,Mobile模块 配置Application/Common/Conf/config.p ...

  5. WPF MVVM初体验

    首先MVVM设计模式的结构, Views: 由Window/Page/UserControl等构成,通过DataBinding与ViewModels建立关联: ViewModels:由一组命令,可以绑 ...

  6. hdu 4033 2011成都赛区网络赛 余弦定理+二分 **

    二分边长,判断最后内角和是否为2pi,注意l与r的选取,保证能组成三角形 #include<cstdio> #include<iostream> #include<alg ...

  7. servlet、genericservlet、httpservlet之间的区别

    转自:http://blog.csdn.net/rat9912345/article/details/5161789 当编写一个servlet时,必须直接或间接实现servlet接口,最可能实现的方法 ...

  8. Android使用JNI实现Java与C之间传递数据(转)

    介绍Java如何将数据传递给C和C回调Java的方法.  java传递数据给C,在C代码中进行处理数据,处理完数据后返回给java.C的回调是Java传递数据给C,C需要用到Java中的某个方法,就需 ...

  9. Linux内核system_call中断处理过程

    “平安的祝福 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” men ...

  10. AS项目转到eclipse中方法

    手工改,1.在eclipse 上新建一个空的项目;2.点击android studio 中的android 视图,        a.替换as 中的AndroidManifest.xml ->  ...