1 条题解
-
0
1. 问题分析
我们需要在已有若干不重叠矩形的墙面上,找到一个新的矩形位置,满足:
- 不与任何现有矩形重叠
- 不超出墙面边界
- 存在多解时选择最靠下(y最小)、其次最靠左(x最小)的位置
2. 关键观察
- 候选位置生成:新矩形的左下角只能出现在以下位置:
- 现有矩形的左右边界延伸线
- 现有矩形的上下边界延伸线
- 墙面边界
- 剪枝优化:只需检查关键坐标点形成的网格,无需遍历所有像素点
3. 算法选择
采用离散化+暴力检查的方法:
graph TD A[收集所有关键x/y坐标] --> B[排序并去重] B --> C[生成候选位置网格] C --> D[检查每个候选位置] D --> E{是否有效?} E -->|是| F[记录最优位置] E -->|否| D F --> G[输出结果]
4. 具体实现步骤
-
输入处理:
- 读取已挂画作的坐标
- 收集所有x和y方向的边界坐标
-
离散化处理:
// 示例代码 sort(x_coords.begin(), x_coords.end()); x_coords.erase(unique(x_coords.begin(), x_coords.end()), x_coords.end());
-
候选位置生成:
- 对每个x坐标和y坐标的组合(x,y)
- 计算可能的新矩形区域:(x,y)到(x+w',y+h')
-
有效性检查:
- 边界检查:不超出墙面
- 重叠检查:与所有现有矩形无交集
bool isOverlap(const Rect& a, const Rect& b) { return !(a.x2 <= b.x1 || b.x2 <= a.x1 || a.y2 <= b.y1 || b.y2 <= a.y1); }
-
最优解选择:
- 维护当前最优解(best_x, best_y)
- 按y升序、x升序比较
5. 复杂度分析
步骤 时间复杂度 空间复杂度 坐标收集 O(n) O(n) 排序去重 O(n log n) 候选检查 O(n^3) O(1) 总计 O(T*n^3) O(n) 6. 优化技巧
- 提前终止:找到第一个有效位置后不立即退出,继续寻找更优解
- 智能排序:按y从小到大、x从小到大顺序检查候选位置
- 快速IO:使用
ios::sync_with_stdio(false)
加速输入输出
7. 边界情况处理
- 无挂画:直接检查墙面是否容纳新画作
- 新画作尺寸等于墙面:仅当没有挂画时可行
- 最小尺寸画作:1x1的画作总能找到空隙
8. 示例推演
输入:
1 2 10 10 1 1 3 3 7 7 9 9 2 2
处理过程:
- 收集x坐标:[0,1,3,7,9,10]
- 收集y坐标:[0,1,3,7,9,10]
- 检查候选位置:
- (0,0)→(2,2) ✔
- (0,3)→(2,5) ✔
- (3,0)→(5,2) ✔
- ...
- 最优解:(0,0)
输出:
0 0
9. 为什么不用高级数据结构?
- 题目限制n≤200,O(n^3)完全可接受
- 使用线段树等结构会增加实现复杂度
- 离散化后暴力检查足够高效
标程
#include <iostream> #include <vector> #include <algorithm> #include <climits> using namespace std; struct Painting { int x1, y1, x2, y2; }; bool isOverlap(const Painting& a, const Painting& b) { return !(a.x2 <= b.x1 || b.x2 <= a.x1 || a.y2 <= b.y1 || b.y2 <= a.y1); } // 自定义 unique 函数替代 C++11 的 std::unique template <typename T> typename vector<T>::iterator my_unique(vector<T>& vec) { if (vec.empty()) return vec.end(); typename vector<T>::iterator result = vec.begin(); for (typename vector<T>::iterator it = vec.begin() + 1; it != vec.end(); ++it) { if (*it != *result) { *(++result) = *it; } } return ++result; } void solve() { int T; cin >> T; while (T--) { int n, w, h; cin >> n >> w >> h; vector<Painting> paintings(n); vector<int> x_coords, y_coords; // 添加墙面边界作为候选坐标 x_coords.push_back(0); x_coords.push_back(w); y_coords.push_back(0); y_coords.push_back(h); for (int i = 0; i < n; ++i) { cin >> paintings[i].x1 >> paintings[i].y1 >> paintings[i].x2 >> paintings[i].y2; x_coords.push_back(paintings[i].x1); x_coords.push_back(paintings[i].x2); y_coords.push_back(paintings[i].y1); y_coords.push_back(paintings[i].y2); } // 排序并去重坐标 sort(x_coords.begin(), x_coords.end()); x_coords.erase(my_unique(x_coords), x_coords.end()); sort(y_coords.begin(), y_coords.end()); y_coords.erase(my_unique(y_coords), y_coords.end()); int new_w, new_h; cin >> new_w >> new_h; bool found = false; int best_x = INT_MAX, best_y = INT_MAX; // 检查所有可能的候选位置 for (size_t i = 0; i < x_coords.size(); ++i) { for (size_t j = 0; j < y_coords.size(); ++j) { int x = x_coords[i]; int y = y_coords[j]; int x_end = x + new_w; int y_end = y + new_h; // 检查是否超出墙面边界 if (x_end > w || y_end > h) continue; Painting new_painting; new_painting.x1 = x; new_painting.y1 = y; new_painting.x2 = x_end; new_painting.y2 = y_end; // 检查是否与现有画作重叠 bool valid = true; for (size_t k = 0; k < paintings.size(); ++k) { if (isOverlap(new_painting, paintings[k])) { valid = false; break; } } // 更新最优解 if (valid) { found = true; if (y < best_y || (y == best_y && x < best_x)) { best_y = y; best_x = x; } } } } if (found) { cout << best_x << " " << best_y << endl; } else { cout << "Fail!" << endl; } } } int main() { ios::sync_with_stdio(false); cin.tie(0); // C++98 中使用 0 代替 nullptr solve(); return 0; }
- 1
信息
- ID
- 1473
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者