题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=2561
做法
做这道题的时候,我想起了以前同学给我讲最小生成树的一个性质,基于kruskal的做法。
当你要加入一条边时,边权小于它的边一定都over了,而且哪些点构成一个联通块是确定了的,注意是小于,不是小于等于。
那么有了这个性质之后,这道题就非常easy了,考虑这条边能在最小生成树中,那么边权小于它的边连入之后这两个点一定还未联通,如果已经联通,就要删去最小数量的边使他联通,那么我们想就想到了最小割,所以图建出来跑一下最大流就行了,最大生成树的话同理,只要把大于它的边拿出来建图就行了。
代码
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#define LL long long
#define N (20005)
#define M (200005)
using namespace std;
int n,m,u,v,w,tot,S,T,ans;
int son[M<<1],nxt[M<<1],f[M<<1],head[N],cur[N],h[N],co[N];
struct node{
int x,y,z;
}a[M];
template <typename T> void read(T&t) {
t=0;
bool fl=true;
char p=getchar();
while (!isdigit(p)) {
if (p=='-') fl=false;
p=getchar();
}
do {
(t*=10)+=p-48;p=getchar();
}while (isdigit(p));
if (!fl) t=-t;
}
inline bool cmp(node a,node b){
return a.z<b.z;
}
inline void add(int x,int y,int z){
//printf("%d %d\n",x,y);
son[++tot]=y,f[tot]=z,nxt[tot]=head[x],head[x]=tot;
}
int DFS(int u,int maxflow){
if (u==T) return maxflow;
int used=0;
for (int p=cur[u];~p;p=nxt[p]){
cur[u]=p;
int v=son[p];
if (f[p]>0&&h[v]+1==h[u]){
int now=DFS(v,min(maxflow-used,f[p]));
used+=now;
f[p]-=now;
f[p^1]+=now;
}
if (used==maxflow) return maxflow;
}
cur[u]=head[u];
if (--co[h[u]]==0){
h[S]=n;
}
h[u]++;
co[h[u]]++;
return used;
}
int main(){
read(n),read(m);
for (int i=1;i<=m;i++){
read(a[i].x),read(a[i].y),read(a[i].z);
}
sort(a+1,a+m+1,cmp);
read(u),read(v),read(w);
tot=1;
S=u,T=v;
memset(head,-1,sizeof(head));
memset(cur,-1,sizeof(cur));
memset(h,0,sizeof(h));
co[0]=n;
for (int i=1;i<=m&&a[i].z<w;i++){
add(a[i].x,a[i].y,1);
add(a[i].y,a[i].x,1);
}
while (h[S]<n) ans+=DFS(S,10000007);
//puts("stop");
tot=1;
memset(head,-1,sizeof(head));
memset(cur,-1,sizeof(cur));
memset(h,0,sizeof(h));
memset(co,0,sizeof(co));
co[0]=n;
for (int i=m;i>=1&&a[i].z>w;i--){
add(a[i].x,a[i].y,1);
add(a[i].y,a[i].x,1);
}
while (h[S]<n) ans+=DFS(S,10000007);
printf("%d",ans);
return 0;
}