1 条题解
-
0
题目大意
有
N个会议(区间)和K个会议室。如果两个会议在未取消的情况下,通过区间重叠或传递关系相连,则它们必须放在不同的会议室。问通过取消一些会议(代价为违约金),使得剩余会议能满足会议室分配要求的最小总代价。核心观察
-
相关会议形成连通分量
根据规则,相关关系具有传递性。所有未取消的会议会形成若干个连通块(连通分量)。 -
分量独立处理
不同连通分量之间互不影响,可以独立处理。 -
贪心策略
对于一个大小为m的连通分量:- 如果
m <= K,不需要取消任何会议。 - 如果
m > K,必须取消至少m - K个会议。最优策略是取消该分量中违约金最小的m - K个会议。
- 如果
算法步骤
-
构建图并找连通分量
- 将每个会议视为节点。
- 如果两个会议区间重叠(
max(S[i], S[j]) < min(E[i], E[j])),则连边。 - 使用 BFS/DFS 或并查集找出所有连通分量。
-
计算最小代价
- 对每个连通分量:
- 若分量大小
m <= K,代价增加0。 - 若
m > K,将该分量内所有会议的违约金排序,取最小的m - K个求和,加入总代价。
- 若分量大小
- 对每个连通分量:
-
返回总代价
复杂度分析
- 建图:
O(N²)(判断每对区间是否重叠) - 找连通分量:
O(N²) - 排序:每个分量内部排序,总复杂度
O(N log N) - 总体:
O(N²),在N <= 2500时可行
代码实现(C++ 核心逻辑)
#include <vector> #include <algorithm> #include <functional> #include <queue> using namespace std; long long min_charge(int K, vector<int> S, vector<int> E, vector<int> W) { int N = S.size(); vector<vector<int>> graph(N); // 建图 for (int i = 0; i < N; i++) { for (int j = i + 1; j < N; j++) { if (max(S[i], S[j]) < min(E[i], E[j])) { graph[i].push_back(j); graph[j].push_back(i); } } } // 找连通分量 vector<bool> visited(N, false); long long ans = 0; for (int i = 0; i < N; i++) { if (!visited[i]) { vector<int> component; queue<int> q; q.push(i); visited[i] = true; while (!q.empty()) { int u = q.front(); q.pop(); component.push_back(u); for (int v : graph[u]) { if (!visited[v]) { visited[v] = true; q.push(v); } } } // 处理当前分量 int m = component.size(); if (m > K) { vector<int> weights; for (int idx : component) { weights.push_back(W[idx]); } sort(weights.begin(), weights.end()); for (int j = 0; j < m - K; j++) { ans += weights[j]; } } } } return ans; }关键点
- 问题本质:在区间图中,删除代价最小的顶点使得每个连通分量大小不超过 K
- 核心算法:连通分量 + 贪心
- 优化方向:对于大规模数据,可使用扫描线优化建图过程
-
- 1
信息
- ID
- 5277
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者