CF28A - Bender Problem(模拟 + *1600)
CF28A - Bender Problem(源地址自⇔CF28A)
tag
⇔模拟、⇔*1600
题意
按顺序给出 \(N\) 个钉子(保证相邻两个钉子之间的连线平行于坐标轴,且没有三个钉子位于同一直线上),现在给出 \(M\) 根金属棒,你需要使用金属棒将这些钉子依次围起来,使得围成的图形封闭。规定如下:
- 每根金属棒必须 \(90°\) 弯折一次(在任意整数位置);
- 允许金属棒重叠;
- 弯折位置和两端都需要固定到钉子上,弯折位置所固定的钉子上不能固定另外的金属棒。
不需要使用全部的金属棒,你需要输出一种可能的围绕方式,格式为: \(N\) 个数字,代表 \(N\) 个钉子每个钉子上放置的金属棒编号,若某个钉子上放置的为两根金属棒的两端,则输出 \(-1\) 。
一组样例,满足 \(4 \le N \le 500\) 且为偶数,金属棒的数量 \(2 \le M \le 500\) 且长度 \(1 \le len_M \le 2*10^5\) ,钉子的坐标 \(-10^4 \le x,y \le 10^4\) 。
思路
赛时思路
这道题最主要的难点在于理解明白题目意思,之后的实现并无难度,故略。
AC代码
点击查看代码
const int N = 2e5 + 7;
int x[N], y[N], mp[N];
int v[N], ans[N], flag;
int clac(int i, int j) {
return abs(x[i] - x[j]) + abs(y[i] - y[j]);
}
int main() {
int n, m; cin >> n >> m;
for (int i = 1; i <= n; ++ i) cin >> x[i] >> y[i];
for (int i = 1; i <= m; ++ i) cin >> mp[i];
x[n + 1] = x[1], y[n + 1] = y[1];
x[0] = x[n], y[0] = y[n]; //这里写成 x 了,卡了好几个小时...
for (int t = 1; t <= 2; ++ t) {
flag = 0;
memset(v, 0, sizeof v);
memset(ans, -1, sizeof ans);
for (int i = t; i <= n; i += 2) {
int len = clac(i, i - 1) + clac(i, i + 1);
for (int j = 1; j <= m; ++ j) { //由于数据量较小,此处我们选择遍历所有金属棒
if (v[j] == 0 && mp[j] == len) {
v[j] = 1;
ans[i] = j;
break;
}
}
if (ans[i] == -1) flag = 1;
}
if (flag == 0) {
cout << "YES" << endl;
for (int i = 1; i <= n; ++ i) cout << ans[i] << " ";
return 0;
}
}
cout << "NO\n";
}
错误次数
(补题 1 次)未考虑钉子坐标为负数的情况,直接作为下标储存(以为相邻钉子是需要自己找的,所以使用了数组储存、寻找),导致 RE 。
(补题 4 次)在初始处理时写错数组。
文 / WIDA
2022.03.26 成文
首发于WIDA个人博客,仅供学习讨论