2024 ICPC Asia Taichung Regional Contest C. Cube
题意
给定一个 \(n \times n \times n\) 的立方体,
从里面选取 \(n\) 个数, 要求两两不在同一平面内, 所以总共会有 \(n\) 个数被选.
求能够选取的最小值.
其中 \(2 \le n \le 12,\ 0 \le val_{x,y,z} \le 2 \times 10^7\).
算法
动态规划, 状态压缩.
思路
题目要求求能够选取的最小值, 考虑动态规划 / 贪心.
模拟几组样例可以发现, 贪心行不通, 只得使用动态规划.
又观察到 \(2 \le n \le 12\), 可以考虑利用状态压缩进行转移.
令 \(f_{s_x,s_y}\) 表示 \(s_x, s_y\) 这两个 \(\{0,1\}\) 集合所表示的坐标的方格已经被选了(1 表示被选).
那么可以得到以下转移方程:
\[f_{s_x,s_y} = \min(f_{s_x \oplus (2^i),s_y \oplus (2^j)})+val_{popcount(s_x)-1,i,j}
\]
其中当且仅当 \(popcount(s_x)=popcount(s_y)\) (即两集合中 1 的个数相等)且 \(s_x\) 的第 \(i\) 位为 1 以及 \(s_y\) 的第 \(j\) 位为 1 才能转移.
转移前记得将数组赋值成极大值.
#pragma GCC optimize("Ofast")
#include "iostream"
using namespace std;
constexpr int N = 13, M = 1 << 12;
int n, a[N][N][N];
int f[M][M];
inline void init()
{
cin >> n;
for (int i = 0; i ^ n; ++i)
for (int j = 0; j ^ n; ++j)
for (int k = 0; k ^ n; ++k)
cin >> a[i][j][k];
return;
}
inline void calculate()
{
for (int i = 1; i ^ (1 << n); ++i)
for (int j = 1; j ^ (1 << n); ++j)
{
f[i][j] = 1e9;
int num = __builtin_popcount(i);
if (num ^ __builtin_popcount(j)) [[likely]]
continue;
for (int k = 0; k ^ n; ++k)
{
if (!(i >> k & 1)) [[likely]]
continue;
for (int l = 0; l ^ n; ++l)
if (j >> l & 1) [[unlikely]]
f[i][j] = min(f[i][j], f[i ^ (1 << k)][j ^ (1 << l)] + a[num - 1][k][l]);
}
}
cout << f[(1 << n) - 1][(1 << n) - 1] << '\n';
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
cin.tie(nullptr)->ios::sync_with_stdio(false);
solve();
return 0;
}
分类:
题目总结
, 题目总结 / 2024. 10~12月
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现