【NOIP2017提高组正式赛】宝藏 题解
题目大意
这道题目题目大意就是说,有一个图
G
=
(
V
,
E
)
G=(V,E)
G=(V,E),求一个子图
G
′
=
(
V
,
E
′
)
G'=(V,E')
G′=(V,E′),满足
E
′
=
V
−
1
E'=V-1
E′=V−1,也就是一棵树。
然后每一次一条边建出来的花费就是长度乘以这条边起点的深度加一。
求最小花费。
解题方法
关键词:状态压缩动态规划
设
f
i
,
j
f_{i,j}
fi,j表示现在这棵树的深度为
i
i
i,整棵树的状态(用
0
/
1
0/1
0/1表示)为
j
j
j时,的最小花费。
画一个图好看一点。
那么显然可以从上一个转移过来。
设
k
k
k表示第
i
i
i层的结点。
则上一层的状态就是
f
i
−
1
,
k
⊕
j
f_{i-1,k\oplus {j}}
fi−1,k⊕j。
画个图就显然了。
设
g
p
,
q
g_{p,q}
gp,q表示从
1
1
1到某层的上一层的状态为
p
p
p,这一层的状态为
q
q
q。
那么转移就是
f
i
,
j
=
min
k
⊆
j
f
i
−
1
,
j
⊕
k
+
g
j
⊕
k
,
k
×
(
i
−
1
)
\begin{aligned}f_{i,j}=\min_{k\subseteq j}f_{i-1,j\oplus k}+g_{j\oplus k,k}\times(i-1)\end{aligned}
fi,j=k⊆jminfi−1,j⊕k+gj⊕k,k×(i−1)
看上图就懂了。
然后考虑如何求
g
g
g。
首先
q
q
q一定是
p
p
p的补集的子集,也就是
q
⊆
∁
S
p
q\subseteq\complement_Sp
q⊆∁Sp(设全集(总状态)为
S
S
S),原因很简单。
所以枚举
q
q
q一定是
p
⊕
S
p\oplus S
p⊕S的子集(子状态)。
然后我们把状态
q
q
q中所有点都得算一遍,这样就得到了
g
p
,
q
g_{p,q}
gp,q从
g
p
,
q
⊕
l
o
w
b
i
t
(
q
)
g_{p,q\oplus lowbit(q)}
gp,q⊕lowbit(q)转移过来。
l
o
w
b
i
t
(
i
)
lowbit(i)
lowbit(i)表示二进制
i
i
i从末尾开始第一个
1
1
1所构成的数。
也就是每一次选出一个二进制状态为
l
o
w
b
i
t
(
q
)
lowbit(q)
lowbit(q)的点,算这个点的贡献。
这个点设为
x
x
x,其实
x
=
log
2
l
o
w
b
i
t
(
q
)
+
1
x=\log_{2}^{lowbit(q)}+1
x=log2lowbit(q)+1,原因是我们点是从
1
1
1开始计数的,而二进制状态是从
0
0
0次方开始的。
而贡献就是状态
p
p
p任意一个点到
x
x
x的最小距离。
如图
所以可得
g
p
,
q
=
g
p
,
q
⊕
l
o
w
b
i
t
(
j
)
+
min
k
∈
p
c
k
,
x
\begin{aligned}g_{p,q}=g_{p,q\oplus lowbit(j)}+\min_{k\in p}{c_{k,x}}\end{aligned}
gp,q=gp,q⊕lowbit(j)+k∈pminck,x
c
i
,
j
c_{i,j}
ci,j为
i
i
i到
j
j
j的最小花费。
技巧
假若要枚举 S S S的子集,可以用以下代码:
for(int i=S;i;i=(i-1)&S)
但是这样做 i i i是不断递减的,所以如果要从小到大枚举要存一个数组再反过来。