卧薪尝胆,厚积薄发。
最小生成树
Date: Tue Dec 11 07:58:56 CST 2018 In Category: NoCategory

Description:

给出一个带权无向图和一条不在图中的边,询问至少要删掉原图中的几条边可以使得这条边既在最小生成树中也在最大生成树中。
$1\leqslant n\leqslant 2\times 10^4$

Solution:

在最小生成树中的要求就是不能通过比他更小的边使得 $u$ 和 $v$ 联通,最大生成树类似,于是就分别拿出比他小的边和比他大的边求最小割加在一起就是答案。
要用双向边那种科技。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 20010
#define MAXM 200010
struct edges
{
int u,v,w;
}es[MAXM];
int u,v,w;
namespace DINIC
{
struct edge
{
int to,nxt,f;
}e[MAXM << 1];
int edgenum = 0;
int lin[MAXN];
void add(int a,int b,int f)
{
e[edgenum] = (edge){b,lin[a],f};lin[a] = edgenum++;
e[edgenum] = (edge){a,lin[b],f};lin[b] = edgenum++;
return;
}
int s,t;
void init()
{
s = t = 0;
memset(lin,-1,sizeof(lin));
edgenum = 0;
return;
}
int ch[MAXN];
bool BFS()
{
queue<int> q;q.push(s);
memset(ch,-1,sizeof(ch));ch[s] = 0;
while(!q.empty())
{
int k = q.front();q.pop();
for(int i = lin[k];i != -1;i = e[i].nxt)
{
if(ch[e[i].to] == -1 && e[i].f)
{
ch[e[i].to] = ch[k] + 1;
q.push(e[i].to);
}
}
}
return (ch[t] != -1);
}
int flow(int k,int f)
{
if(k == t)return f;
int r = 0;
for(int i = lin[k];i != -1 && f > r;i = e[i].nxt)
{
if(ch[e[i].to] == ch[k] + 1 && e[i].f)
{
int l = flow(e[i].to,min(e[i].f,f - r));
e[i].f -= l;r += l;e[i ^ 1].f += l;
}
}
if(r == 0)ch[k] = -1;
return r;
}
int dinic()
{
int ans = 0,r;
while(BFS())while(r = flow(s,0x3f3f3f3f))ans += r;
return ans;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&es[i].u,&es[i].v,&es[i].w);
}
scanf("%d%d%d",&u,&v,&w);
int ans = 0;
DINIC::init();
DINIC::s = u;DINIC::t = v;
for(int i = 1;i <= m;++i)
{
if(es[i].w > w)DINIC::add(es[i].u,es[i].v,1);
}
ans += DINIC::dinic();
DINIC::init();
DINIC::s = u;DINIC::t = v;
for(int i = 1;i <= m;++i)
{
if(es[i].w < w)DINIC::add(es[i].u,es[i].v,1);
}
ans += DINIC::dinic();
cout << ans << endl;
return 0;
}
In tag: 图论-dinic
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡