BZOJ 2561: 最小生成树【最小割/最大流】

Description

 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?

Input

  第一行包含用空格隔开的两个整数,分别为N和M;
  接下来M行,每行包含三个正整数u,v和w表示图G存在一条边权为w的边(u,v)。
  最后一行包含用空格隔开的三个整数,分别为u,v,和 L;
  数据保证图中没有自环。

Output

 输出一行一个整数表示最少需要删掉的边的数量。

Sample Input

3 2
3 2 1
1 2 3
1 2 2

Sample Output

1

HINT

对于20%的数据满足N ≤ 10,M ≤ 20,L ≤ 20;
  对于50%的数据满足N ≤ 300,M ≤ 3000,L ≤ 200;
  对于100%的数据满足N ≤ 20000,M ≤ 200000,L ≤ 20000。

Source

2012国家集训队Round 1 day1

思路:首先白书中有这么一个命题:如果在图中存在一个环,使得一条边为环中的最大值,那么这条最大值的边显然不可能是MST中的边,于是猜测了一个相似的命题:如果不存在一个环使得这个边为最大值,那么一定存在一个MST使得这条边为MST中的边

然后仔细想想这个命题好像是有问题的,于是往kruscal方面考虑,如果将边排序了以后从小到大加,则加边过程中u到v显然不能联通,不然就得删边,在看了解题报告后证实了这个想法,于是对于一条边一定存在一个MST使得这条边为MST中的边的充要条件为比这条边小的边一定不能和这条边成环,于是结果就很显然了

#include <stdio.h>

#include <iostream>

#include<queue>

#include <string.h>

#include <algorithm>

#define maxn 1000005

#define maxm 1000005

#define inf 0x3f3f3f3f

int head[maxn],next[maxn],point[maxn],flow[maxn];

int ans=0,now=0,dist[maxn],que[maxn];

using namespace std;

struct T

{

int x;int y;int v;

}a[maxn];

inline bool operator <(T a,T b){return a.v<b.v;}

void add(int x,int y,int v)

{

next[++now]=head[x];

head[x]=now;

point[now]=y;

flow[now]=v;

next[++now]=head[y];

head[y]=now;

point[now]=x;

flow[now]=0;

}

int bfs(int s,int t)

{

memset(dist,-1,sizeof(dist));

dist[s]=0;

int l=0,r=0;

que[++r]=s;

while(l<r)

{

int u=que[++l];

for(int i=head[u];i;i=next[i])

{

if(dist[point[i]]==-1&&flow[i])

{

int k=point[i];

dist[k]=dist[u]+1;

que[++r]=k;

}

}

}

return dist[t]!=-1;

}

int dfs(int s,int d,int t)

{

if(s==t)return d;

int res=0;

for(int i=head[s];i&&res<d;i=next[i])

{

int u=point[i];

if(flow[i]>0 &&dist[u]==dist[s]+1)

{

int dd=dfs(u,min(d-res,flow[i]),t);

if(dd>0)

{

flow[i]-=dd;

flow[((i-1)^1)+1]+=dd;

res+=dd;

}

}

}

if(res==0)dist[s]=-1;

return res;

}

int main()

{

int n,m,s,t,l;

scanf("%d%d",&n,&m);

for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);

scanf("%d%d%d",&s,&t,&l);

sort(a+1,a+1+m);

for(int i=1;i<=m;i++)

{

if(a[i].v>l)

{

add(a[i].x,a[i].y,1);

add(a[i].y,a[i].x,1);

}

}

while(bfs(s,t))

{

ans+=dfs(s,inf,t);

}

now=0;

memset(head,0,sizeof(head));

for(int i=1;i<=m;i++)

{

if(a[i].v<l)

{

add(a[i].x,a[i].y,1);

add(a[i].y,a[i].x,1);

}

}

while(bfs(s,t))

{

ans+=dfs(s,inf,t);

}

printf("%d\n",ans);

return 0;

}

时间: 2024-10-25 00:12:12

BZOJ 2561: 最小生成树【最小割/最大流】的相关文章

BZOJ 2561: 最小生成树(最小割)

U,V能在最小(大)生成树上,当且仅当权值比它小(大)的边无法连通U,V. 两次最小割就OK了. --------------------------------------------------------------------- #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<que

BZOJ 2521 最小生成树(最小割)

http://www.lydsy.com/JudgeOnline/problem.php?id=2521 题意:每次能增加一条边的权值1,求最小代价让一条边保证在最小生成树里 思路:如果两个点中有环,那么这条边必须不能是环的最大边,这样子把之前所有的边权值变成V+1-v[i],无向图网络流就可以了 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5

BZOJ 2561 最小生成树(最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2561 题意:给定一个边带正权的连通无向图G= (V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树 上? 思路:考虑克鲁斯卡尔算法的过程.若加入的 边(u,v,L)能够出现在最小生成树中,那么权值小于L的边

【BZOJ-1797】Mincut 最小割 最大流 + Tarjan + 缩点

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1685  Solved: 724[Submit][Status][Discuss] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案

ZOJ3792_Romantic Value(网络流/最小割=最大流/找割边)

解题报告 题目传送门 题意: 给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少. 求出一个比值:剩余边数权值和/删除的边数. 思路: 明显的让起点终点达不到就是一个最小割,用最大流可以求出. 但是求割边边数就不会了,没做过最小割的求割边问题. 割边一定是残留网络中零流的边,但零流不一定是割边. 飞神的想法很奇特.链接传送 可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流.最后流量一定等于割边边数 另外: 还有一

Destroying The Graph 最小点权集--最小割--最大流

Destroying The Graph 构图思路: 1.将所有顶点v拆成两个点, v1,v2 2.源点S与v1连边,容量为 W- 3.v2与汇点连边,容量为 W+ 4.对图中原边( a, b ), 连边 (a1,b2),容量为正无穷大 则该图的最小割(最大流)即为最小花费. 简单证明: 根据ST割集的定义,将顶点分成两个点集.所以对于原图中的边(a,b),转换成 S->a1->b2->T. 则此时路径必定存在 一条割边,因为a1->b2为无穷大,所以割边必定是 S->a1

POJ3469_Dual Core CPU(网络流/最小割=最大流/模版)----Dinic模版2.0

解题报告 题目传送门 题意: 双核CPU,n个模块,每个模块必须运行在某个CPU核心上,每个模块在cpu单核的消耗A和B,M对模块要共享数据,如果在同一个核心上不用消耗,否则需要耗费.安排N个模块,使得总耗费最小 思路: 将两个cpu核心看成源点和汇点,其他模块分别与源点汇点连线(表示每个模块可以在任意cpu上运行),m对模块分别连双向边,要使得模块只能在一个cpu上运行,就是找到一个割,源点和汇点必不联通,耗费最少就是最小割,最小割最大流原理转换成求最大流. 这题数据大,没优化TLE了,加了两

BZOJ 2561 最小生成树 | 网络流 最小割

链接 BZOJ 2561 题解 用Kruskal算法的思路来考虑,边(u, v, L)可能出现在最小生成树上,就是说对于所有边权小于L的边,u和v不能连通,即求最小割: 对于最大生成树的情况也一样.容易看出两个子问题是各自独立的,把两个最小割相加即可. #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <queue> using

bzoj 2561: 最小生成树【最小割】

看错题了以为多组询问吓得不行-- 其实还挺好想的,就是数据范围一点都不网络流.把U作为s,V作为t,以最小生成树为例,(U,V,L)要在最小生成树上,就要求所有边权比L小的边不能连通(U,V)所在的联通块.这样一来模型就很显然了,就是对所有边权<L的边建边(u,v,1)(v,u,1),然后最小割即可.建双向边是因为反正只会割掉一条-- #include<iostream> #include<cstdio> #include<cstring> #include<

BZOJ 2561 最小生成树 【最大流】

Description 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条边权为L的边(u,v),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上? Solution 题意:在一个图中,问一条边即在最小生成树上,又在最大生成树上需要从图上删掉多少条边 在最小生成树上,一条边不被选择的充要条件是什么呢? 当比它小的边已经将它所连接的两点连接起来的时候,这