最小斯坦纳树
老是忘掉这个东西,稍微记一下。
不难观察得到最终答案是一棵树。
涉及到树形的 dp 和状压,考虑状态 表示 为树根,目前连接起来的点状态为 的最小代价。
转移分两种:
- 树根 :。
- 两棵子树合并:。
考虑按大小顺序枚举 ,第一种相当于最短路,第二种枚举子集,时间复杂度 。用了 SPFA 求最短路。
#include <bits/stdc++.h> #define pb emplace_back #define fir first #define sec second using i64 = long long; using u64 = unsigned long long; using pii = std::pair<int,int>; const i64 mod = 998244353; const int maxn = 505; const int maxm = 1 << 10; int f[maxm][maxn], n, m, k; bool inq[maxn]; std::vector<pii> G[maxn]; std::queue<int> q; int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); scanf("%d %d %d", &n, &m, &k); for(int i = 1;i <= m;++ i) { int u, v, t; scanf("%d %d %d", &u, &v, &t); G[u].pb(v, t); G[v].pb(u, t); } memset(f, 0x3f, sizeof(f)); for(int i = 1;i <= k;++ i) { int x; scanf("%d", &x); f[1 << (i - 1)][x] = 0; } for(int S = 1;S < (1 << k);++ S) { for(int T = (S - 1) & S;T;T = (T - 1) & S) { for(int i = 1;i <= n;++ i) f[S][i] = std::min(f[S][i], f[T][i] + f[S ^ T][i]); } for(int i = 1;i <= n;++ i) q.emplace(i), inq[i] = true; int mn = 0x3f3f3f3f, pos = 0; while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; for(auto& [v, w] : G[u]) if(f[S][v] > f[S][u] + w) { f[S][v] = f[S][u] + w; if(!inq[v]) inq[v] = true, q.emplace(v); } } } int ans = 0x3f3f3f3f; for(int i = 1;i <= n;++ i) ans = std::min(f[(1 << k) - 1][i], ans); printf("%d\n", ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2022-07-14 AtCoder Beginner Contest 259 题解