T1:舞会配对
本题难度中等,注意到数据范围很小,正解极有可能是朴素的搜索枚举方法。
记 \(m = 2n\)
使用回溯法,依次考虑第 \(1 \sim m\) 个人,要与谁配对
记录状态:
- 当前考虑配对的人的编号
- 已经配成的对数
- 当前(未完全的)配对方案的幸福度
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
int m = 2*n;
vector<vector<int>> a(m, vector<int>(m));
rep(i, m)rep(j, m) cin >> a[i][j];
ll ans = -1e18;
vector<int> matched(m);
auto dfs = [&](auto& f, int step, int cnt, ll now) -> void {
if (cnt == n) {
ans = max(ans, now);
return;
}
if (matched[step]) {
f(f, step+1, cnt, now);
return;
}
for (int i = step+1; i < m; ++i) {
// 1. 剪枝
if (matched[i]) continue;
// 2. 试探
matched[i] = matched[step] = true;
f(f, step+1, cnt+1, now*a[step][i]);
// 3. 回溯
matched[i] = matched[step] = false;
}
};
dfs(dfs, 0, 0, 1);
cout << ans << '\n';
return 0;
}
如何分析时间复杂度?
\(m = 16\) 的极端情形:
对第 \(1\) 个待配对的人,后续有 \(15\) 个可选的与其配对的人
对第 \(2\) 个待配对的人,后续有 \(13\) 个可选的与其配对的人
对第 \(3\) 个待配对的人,后续有 \(11\) 个可选的与其配对的人
\(~\vdots\)
对第 \(8\) 个待配对的人,后续有 \(1\) 个可选的与其配对的人
由乘法原理,需要枚举的所有配对方案为:
\[15!! = 15 \times 13 \times \cdots \times 3 \times 1 = 2027025
\]
关于本题的背景:
本题为边权之积,可以通过取对数,化积为和。
实质为 二分图最大权匹配问题。
时间复杂度为 \(O(n^3)\)。
适用范围:提高组以上