CodeStar2023年春第3周周赛普及进阶组

发布时间 2023-04-04 21:23:36作者: V_Melville

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)\)
适用范围:提高组以上