bzoj 2561 最小生成树 最小割

2561: 最小生成树

Time Limit: 10 Sec  Memory Limit: 128 MB

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

 

大意:

给出一个图,问要使给出的最后一条边(X,Y,V)既可以在最小生成树又可以在最大生成树上,最少需要删掉几条边。

 

 

思路:

把原问题分割成两个小问题,<1>可以再最小生成树上  <2>可以在最大生成树上

 

对于问题<1>,删掉的边一定是权值小于V的,对于问题<2>,删掉的边一定是权值大于V的,没有交集。

 

求解<1>:拿出权值小于V的边建双向流量边(正向和反向流量上限都为1),然后跑最大流,得到最小割,删掉最小割割集中的边就是删边的最优方案。

因为这样是使X和Y不连通的最小代价。

对于问题<2>同理,两个答案相加即可。

 

 1 /*
 2 Welcome Hacking
 3 Wish You High Rating
 4 */
 5 #include<iostream>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<ctime>
 9 #include<cstdlib>
10 #include<algorithm>
11 #include<cmath>
12 #include<string>
13 using namespace std;
14 const int INF=(1LL<<31)-1;
15 int read(){
16     int xx=0,ff=1;char ch=getchar();
17     while(ch>'9'||ch<'0'){if(ch=='-')ff=-1;ch=getchar();}
18     while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();}
19     return xx*ff;
20 }
21 inline int mymin(const int &A,const int &B)
22 {if(A<B)return A;return B;}
23 const int maxn=20010,maxm=200010;
24 int N,M,lin[maxn],len;
25 struct edge{
26     int y,next,flow;
27 }e[maxm<<1];
28 inline void insert(int xx,int yy,int ff){
29     e[++len].next=lin[xx];
30     lin[xx]=len;
31     e[len].y=yy;
32     e[len].flow=ff;
33 }
34 struct Edge{
35     int x,y,v;
36 }E[maxm];
37 int ans=0,SS,TT,VV;
38 int level[maxn],q[maxn],head,tail;
39 void build(bool sgn){
40     memset(lin,0,sizeof(lin));len=0;
41     for(int i=1;i<=M;i++)
42         if(E[i].v<VV&&!sgn)
43             insert(E[i].x,E[i].y,1),insert(E[i].y,E[i].x,1);
44         else if(E[i].v>VV&&sgn)
45             insert(E[i].x,E[i].y,1),insert(E[i].y,E[i].x,1);
46 }
47 bool makelevel(){
48     memset(level,-1,sizeof(level));
49     head=tail=0;
50     q[head]=SS;
51     level[SS]=0;
52     for(;head<=tail;head++)
53         for(int i=lin[q[head]];i;i=e[i].next)
54             if(e[i].flow&&level[e[i].y]==-1){
55                 level[e[i].y]=level[q[head]]+1;
56                 q[++tail]=e[i].y;
57             }
58     return level[TT]!=-1;
59 }
60 int max_flow(int x,int flow){
61     if(x==TT)
62         return flow;
63     int maxflow=0,d;
64     for(int i=lin[x];i&&flow>maxflow;i=e[i].next)
65         if(level[e[i].y]==level[x]+1&&e[i].flow){
66             d=max_flow(e[i].y,mymin(e[i].flow,flow-maxflow));
67             if(d){
68                 maxflow+=d;
69                 e[i].flow-=d;
70                 if(i&1)
71                     e[i+1].flow+=d;
72                 else
73                     e[i-1].flow+=d;
74             }
75         }
76     if(!maxflow)
77         level[x]=-1;
78     return maxflow;
79 }
80 void dinic(){
81     int d;
82     while(makelevel())
83         while((d=max_flow(SS,INF)))
84             ans+=d;
85 }
86 int main(){
87     //freopen("in.txt","r",stdin);
88     N=read(),M=read();
89     for(int i=1;i<=M;i++)
90         E[i].x=read(),E[i].y=read(),E[i].v=read();
91     SS=read(),TT=read(),VV=read();
92     build(0);
93     dinic();
94     build(1);
95     dinic();
96     printf("%d\n",ans);
97     return 0;
98 }
View Code

 

 

posted @ 2018-03-29 16:23  咸鱼lzh  阅读(215)  评论(0编辑  收藏  举报