1. 程式人生 > 其它 >CF28A - Bender Problem(模擬 + *1600)

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個人部落格,僅供學習討論