正题
Portal
这种思想值得学习!
我们知道最小割会将集合分为两部分S集和T集。
考虑随意选出两个点
A
,
B
A,B
A,B,显然在一个最小割中这两个点要么在同一个集合,要么不在同一个集合。
在同一个集合十分好做:我们只需要将这两个点合并起来看作一个点考虑就可以了(边加权合并),因为可以简单分析得到,对于任意的一个点
C
C
C,要么与
A
,
B
A,B
A,B在同一个集合,要么不在同一个集合。
如果我们知道不在同一个集合怎么做,我们就可以每次选两个点出来求一遍答案,然后合并(即考虑在同一个集合的答案),然后求所有这样答案的最小值即可,一共合并
n
−
1
n-1
n−1次。
做法依赖于一个集合
V
V
V,我们将当前与
V
V
V中的直接连边权值最大的点加入
V
V
V中(第一个无所谓),形成了一个排列,有定理:排列的最后一个点与前面点的最小割为最后一个点加入V时的权值。
我们先规定一些记号,在作证明:
1.记
w
(
V
,
x
)
w(V,x)
w(V,x)表示集合
V
V
V中与
x
x
x的直接连边权值和。
2.记
V
x
V_x
Vx表示
x
x
x前的点,不包括
x
x
x。
2.记
W
(
x
)
W(x)
W(x)表示
x
x
x与排列在其前面的直接连边权值和,也就是x加入排列时的权值。
3.记
C
C
C为排列最后一个元素的最小割边集。
4.若点
x
x
x满足排列中的前一个点
y
y
y,与
x
x
x不在同一个集合则称
x
x
x是
a
c
t
i
v
e
active
active的,显然可以发现割
C
C
C将序列分为了很多段,每一段的开始都是一个
a
c
t
i
v
e
active
active节点。
我们先尝试证明一个引理:对于第一个
a
c
t
i
v
e
active
active的点
x
x
x,满足
C
C
C在其前面的部分
≥
W
(
x
)
\geq W(x)
≥W(x)。
“在其前面的部分”指的是排列的前面这一段的诱导子图产生的诱导最小割。
因为
x
x
x是第一个
a
c
t
i
v
e
active
active的点,所以前面的点都不是
a
c
t
i
v
e
active
active的,也就是说,他们都处在同一个连通块内,而
x
x
x与他们处在不同的连通块内,所以至少要割去
W
(
x
)
W(x)
W(x)
定理:对于所有的
a
c
t
i
v
e
active
active的点
x
x
x,满足
C
C
C在其前面的部分
≥
W
(
x
)
\geq W(x)
≥W(x)
在上面的引理已经证明了这个对第一个点肯定满足。
设当前要考虑的
a
c
t
i
v
e
active
active点为
x
x
x,上一个
a
c
t
i
v
e
active
active点为
y
y
y。
可以看到:对于在
x
x
x前面的点来说,到
x
x
x的权值和肯定是
≥
\geq
≥到y的,因为
x
x
x比
y
y
y先加入。
也就是:
w
(
C
x
)
≥
w
(
V
x
,
x
)
≥
w
(
V
x
,
y
)
w(C_x)\geq w(V_x,x) \geq w(V_x,y)
w(Cx)≥w(Vx,x)≥w(Vx,y)
其次,
x
x
x到
y
y
y前这一段都与
y
y
y处于异侧,那么割
C
C
C肯定新包含这些边。
也就是:
w
(
V
y
−
V
x
,
y
)
=
w
(
C
y
)
−
w
(
C
x
)
w(V_y-V_x,y)=w(C_y)-w(C_x)
w(Vy−Vx,y)=w(Cy)−w(Cx)
可以得到:
w
(
V
y
,
y
)
=
w
(
V
y
−
V
x
,
y
)
+
w
(
V
x
,
y
)
≤
w
(
C
y
)
w(V_y,y)=w(V_y-V_x,y)+w(V_x,y)\leq w(C_y)
w(Vy,y)=w(Vy−Vx,y)+w(Vx,y)≤w(Cy)
对于每一个
a
c
t
i
v
e
active
active都满足这样的性质,而最后一个点一定是一个
a
c
t
i
v
e
active
active点,因为在证明
C
C
C为
s
−
t
s-t
s−t割,我们只需要将最后两个点设为
s
,
t
s,t
s,t即可。满足条件
w
(
C
)
≥
w
(
V
t
,
t
)
w(C)\geq w(V_{t},t)
w(C)≥w(Vt,t),而割去t与周围点的连边肯定可以将t与周围点隔开,所以
w
(
C
)
=
w
(
V
t
,
t
)
w(C)=w(V_{t},t)
w(C)=w(Vt,t)。
#include<bits/stdc++.h>
using namespace std;
const int N=610;
int n,m,d[N][N],w[N],a[N];
bool tf[N],vis[N];
int gs(int x){
memset(vis,false,sizeof(vis));
memset(w,0,sizeof(w));w[0]=-1;
for(int i=1;i<=x;i++){
int mx=0;
for(int j=1;j<=n;j++)
if(!tf[j] && !vis[j] && w[mx]<w[j]) mx=j;
a[i]=mx;vis[mx]=true;
for(int j=1;j<=n;j++)
if(!tf[j] && !vis[j]) w[j]+=d[mx][j];
}
tf[a[x]]=true;
for(int i=1;i<=n;i++){
d[a[x-1]][i]+=d[a[x]][i];
d[i][a[x-1]]+=d[i][a[x]];
}
return w[a[x]];
}
int solve(){
int ans=1e9;
for(int i=n;i>=2;i--) ans=min(ans,gs(i));
return ans;
}
int main(){
scanf("%d %d",&n,&m);
int x,y,c;
for(int i=1;i<=m;i++) scanf("%d %d %d",&x,&y,&c),d[x][y]+=c,d[y][x]+=c;
printf("%d\n",solve());
}
本文探讨了一种通过最小割思想解决网络优化问题的方法,通过逐个分析节点并合并最大边权的点,形成排列,利用定理确定每个活跃节点前的最小割。关键步骤包括证明每个活跃节点贡献的最小割价值,并在解决过程中迭代应用。算法核心在于找到最优的连通块划分,降低整体割集成本。
94

被折叠的 条评论
为什么被折叠?



