5.3小测
T4
题解:
因为 \(n \leq 12\),因此可以考虑设计与 \(n\) 相关的指数级算法。
不难发现最终形成的图会是一棵有根树,因此考虑枚举根节点做 dp。
由于一条边的贡献和深度有关,因此设 \(f_{i,S}\) 为深度前 \(i\) 层的节点的集合为 \(S\) 的最小代价。
转移便可以考虑从 \(i-1\) 层的状态转移过来,即:
\[f_{i,S}=\min(f_{i-1,T}+c_{T,S})(T \in S)
\]
其中 \(c_{T,S}\) 表示 \(T\) 通过合并变成 \(S\) 的最小代价。
转移复杂度 \(O(n^2 3^n)\),预处理复杂度 \(O(n^2 3^n)\)。
Code:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 17, U = 1 << 12;
const ll inf = 0x3f3f3f3f;
int n, m;
ll w[N][N], c[U][U];
ll f[N][U];
ll ans = inf;
void DP(int x){
for(int i = 0; i <= n; i++){
for(int S = 0; S < U; S++) f[i][S] = inf;
}
f[0][1 << (x - 1)] = 0;
ll sum = inf;
for(int i = 1; i < n; i++){
for(int S = 1; S < U; S++){
for(int T = S; T; T = (T - 1) & S){
if(S == T) continue;
f[i][S] = min(f[i][S], f[i - 1][T] + i * c[T][S]);
}
if(S == U - 1) sum = min(sum, f[i][S]);
}
}
ans = min(ans, sum);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
memset(w, 0x3f, sizeof(w));
cin >> n >> m;
if(n == 1){
printf("0\n");
return 0;
}
for(int i = 1; i <= m; i++){
int x, y;
ll z;
cin >> x >> y >> z;
w[x][y] = w[y][x] = min(w[x][y], z);
}
for(int S = 1; S < U; S++){
for(int T = S; T; T = (T - 1) & S){
if(S == T) continue;
for(int i = 1; i <= n; i++){
if((S & (1 << (i - 1))) ^ (T & (1 << (i - 1)))){
ll k = inf;
for(int j = 1; j <= n; j++){
if(T & (1 << (j - 1))) k = min(k, w[i][j]);
}
c[T][S] += k;
}
}
}
}
for(int i = 1; i <= n; i++){
DP(i);
}
printf("%lld\n", ans);
return 0;
}
浙公网安备 33010602011771号