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个人博客,仅供学习讨论


posted @ 2022-03-26 19:50  hh2048  阅读(41)  评论(0编辑  收藏  举报