bzoj2561-最小生成树
题目
给定一个边带正权的连通无向图\(G=(V,E)\),其中\(N=|V|\),\(M=|E|\),\(N\)个点从\(1\)到\(N\)依次编号,给定三个正整数\(u\),\(v\),和\(L\) \((u≠v)\),假设现在加入一条边权为\(L\)的边\((u,v)\),那么需要删掉最少多少条边,才能够使得这条边既可能出现在最小生成树上,也可能出现在最大生成树上?
分析
一开始是从最小生成树的Kruskal想,想到了先求两次最小生成树再用优先级求两次最大生成树,后来发现是错的。正解网络流。 若一条边可以出现在最小生成树上,那么就说明比它小的边不能把这两个点联通,最大生成树同理。问题转化成了求比这条边小的边中去掉多少个不联通,于是可以想到用每条边流量为1的最小割。对比\(w\)小和大分别求两次,加起来就是答案。
代码
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<queue>
#define F(x) for (int i=h[x],v=e[i].v,w=e[i].w;~i;i=e[i].nxt,v=e[i].v,w=e[i].w)
using namespace std;
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=2e4+10;
const int maxm=2e5+10;
const int inf=1e9+10;
struct gp {
int u,v,w;
} a[maxm];
struct edge {
int v,w,nxt;
} e[maxm<<2];
int h[maxn],tot=0,nowinf;
void add(int u,int v,int w) {
e[tot]=(edge){v,w,h[u]};
h[u]=tot++;
}
void adde(int u,int v,int w) {
add(u,v,w),add(v,u,0);
}
int dis[maxn];
queue<int> q;
bool bfs(int s,int t) {
q.push(s);
memset(dis,0x3f,sizeof dis);
nowinf=dis[0];
dis[s]=0;
while (!q.empty()) {
int u=q.front();
q.pop();
F(u) if (w>0 && dis[v]==nowinf) {
dis[v]=dis[u]+1;
q.push(v);
}
}
return dis[t]!=nowinf;
}
int Flow(int x,int t,int mi) {
if (x==t) return mi;
int tmp=0;
F(x) if (w>0 && dis[v]==dis[x]+1) {
int now=Flow(v,t,min(mi,w));
mi-=now;
e[i].w-=now;
e[i^1].w+=now;
tmp+=now;
if (mi==0) break;
}
if (!tmp) dis[x]=-1;
return tmp;
}
int maxflow(int s,int t) {
int ret=0;
while (bfs(s,t)) {
ret+=Flow(s,t,inf);
}
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
int n=read(),m=read();
for (int i=1;i<=m;++i) a[i].u=read(),a[i].v=read(),a[i].w=read();
int s=read(),t=read(),w=read();
memset(h,0xff,sizeof h),tot=0;
for (int i=1;i<=m;++i) if (a[i].w<w) adde(a[i].u,a[i].v,1),adde(a[i].v,a[i].u,1);
int fa=maxflow(s,t);
memset(h,0xff,sizeof h),tot=0;
for (int i=1;i<=m;++i) if (a[i].w>w) adde(a[i].u,a[i].v,1),adde(a[i].v,a[i].u,1);
int fb=maxflow(s,t);
int ans=fa+fb;
printf("%d\n",ans);
}