bzoj 2561(最小割)

11 篇文章 0 订阅

2561: 最小生成树

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 1356   Solved: 655
[ Submit][ Status][ Discuss]

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。


解题思路:题目可以转化为,删除一些比L小的边,使得u,v不连通,同理,大于L的也可以处理出最小割,然后求解。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,len,u,v,l,ans;
struct ss
 {
  int x,y,l;
 } a[210000];
int to[1010000],h[21000],f[1010000],next[1010000];
int dis[21000],q[30000];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


bool cmp(ss x,ss y)
 {
  return x.l<y.l;
 }


void insert(int x,int y,int flow)
 {
  ++len; to[len]=y; next[len]=h[x]; h[x]=len; f[len]=flow;
 }


bool bfs()
 {
  memset(dis,-1,sizeof(dis)); dis[u]=1;
  int tail=1,head=0; q[tail]=u;
    while (head<tail)
     {
      ++head;
      int ug=h[q[head]];
      while (ug!=0)
      {
      if (dis[to[ug]]==-1 && f[ug]>0)
      {
      dis[to[ug]]=dis[q[head]]+1;
      ++tail; q[tail]=to[ug];
  }
ug=next[ug];
 }
}
if (dis[v]!=-1) return true; else return false;
 }


int dicnic(int now,int sum)
 {
  if (now==v) return sum;
  int sug=0;
  int ug=h[now];
    while (ug!=0)
     {
      if (f[ug] && dis[to[ug]]==dis[now]+1)
      {
      int s=dicnic(to[ug],min(sum-sug,f[ug]));
      if (s>0)
      {
        sug+=s; f[ug]-=s; f[ug^1]+=s;
  if (sug==sum) return sug;
}
 }
ug=next[ug];
}
if (sug==0) dis[now]=-1; return sug;
 }


int main()
{
n=read(); m=read();
for (int i=1;i<=m;++i)
{
a[i].x=read(); a[i].y=read(); a[i].l=read();
}
sort(a+1,a+m+1,cmp);
u=read(); v=read(); l=read(); len=1;
for (int i=1;i<=m;++i)
{
if (a[i].l>=l) break;
insert(a[i].x,a[i].y,1); insert(a[i].y,a[i].x,1);
}
ans=0;
while (bfs())
{
ans+=dicnic(u,0x7fffffff);
}
memset(h,0,sizeof(h)); len=1;
for (int i=m;i>=1;--i)
{
if (a[i].l<=l) break;
insert(a[i].x,a[i].y,1); insert(a[i].y,a[i].x,1);
}
while (bfs())
     {
      ans+=dicnic(u,0x7fffffff);
}
printf("%d",ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值