• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
The blog of EzSun
lyy && ?
博客园    首页    新随笔    联系   管理    订阅  订阅

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;
}
posted @ 2026-05-06 13:48  EzSun599  阅读(3)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3