Atcoder - 129D vector應用

<Atcoder - 129D> vector應用

https://atcoder.jp/contests/abc129/tasks/abc129_d

題意:

給定一個由 和 組成的矩陣,在點處選擇一個位置放燈,燈光可以在該點處向上下左右四個方向發射,但是碰到#就停止,問可以被燈光輻射到的最大點數。看下樣例1,題意就清楚了,選(2,2)放燈,算上自己最多可以輻射8個點。

思路:

首先看到這種點和#組成的矩陣首先想到深搜和廣搜,但是他只有源點是4個方向發射,被源點輻射到的點都是單一方向的,不適合dfs和bfs的使用條件,而且n和m都是2e3搜索可能會TLE,所以這種思路pass。那麼接下來會想一種暴力的做法,枚舉點的位置,看把當前的點作爲放燈的源點,其所在行所在列分別能輻射到多少個點,然後取一個最大值,這樣複雜度是n^3的依然會TLE。那麼我們想辦法優化這種想法,既然碰到#燈光的輻射就停止了,那麼我們可以先預處理出#的位置,把第i行的#存進vec[i]中,即vec[i][j]表示第i行第j列是#。這樣我們看當前的點在當前行處於哪兩個#之間,這就是它水平方向能輻射的點,列方向也是同理。因此我們需要把邊界都初始化成#,初始化pos = 0,如下圖,(1,1)就是點,那麼它處於 vec[1][0] = 0 和 vec[1][1] = 4 這兩個#之間,所以它能輻射到的點就是4 - 0 - 1 = 3個。點(1,2)和點(1,3)也是同理,都介於vec[1][0] = 0 和 vec[1][1] = 4 這兩個#之間。那麼我現在走到(1,4)是#了,那麼pos往前前進一位,即pos++,這樣我走到(1,5)又是點了,點(1,5)就介於vec[1][1] = 4 和 vec[1][2] = 7之間(這也是我們初始化邊界都爲#的原因,目的是讓每個點都能被兩個#夾在中間,這樣vec的相鄰元素做差就能求出燈光輻射到的點的個數),這樣點(1,5)水平方向能輻射到的點就是7 - 4 - 1 = 2個。這是水平方向,豎直方向同理,另一個vector存放第j列的#,依舊每列都先初始化pos = 0,看當前列找到的點在該列中處於那兩個#之間。

看下核心代碼:

(1) 這步是把#的座標都預處理存進行和列的兩個vector中,vec1[i]表示第i行的#的位置,vec2[j]表示第j列的#的位置

for(int i = 0; i <= n + 1; i++) {
	for(int j = 0; j <= m + 1; j++) {
		if(s[i][j] == '#') {
			vec1[i].push_back(j);
			vec2[j].push_back(i);
		}
	}
}

(2) 這步是枚舉每行的點,看該行的點介於哪兩個#之間

for(int i = 1; i <= n; i++) {
	pos = 0;
	for(int j = 1; j <= m; j++) {
		if(s[i][j] == '.') {
			res[i][j] += vec1[i][pos + 1] - vec1[i][pos] - 1; //相鄰兩個#之間.的個數
		}
		else pos++;
	}
}

(3) 這步是枚舉每列的點,看該列的點介於哪兩個#之間

for(int j = 1; j <= m; j++) {
	pos = 0;
	for(int i = 1; i <= n; i++) {
		if(s[i][j] == '.') {
			res[i][j] += vec2[j][pos + 1] - vec2[j][pos] - 1; //相鄰兩個#之間.的個數
		}
		else pos++;
	}
}

ps:每個點對應的的res[i][j]要減1之後再和ans比較,因爲源點這個位置被行列都輻射了一遍,多算了一次。

AC代碼:

#include <bits/stdc++.h>
using namespace std;
const int maxx = 2e3 + 7;
int n, m, ans;
char s[maxx][maxx];
int res[maxx][maxx];
vector <int> vec1[maxx]; //每行#座標
vector <int> vec2[maxx]; //每列#座標

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 0; i <= n + 1; i++) { //目的是把邊界都初始化成#
		for(int j = 0; j <= m + 1; j++) s[i][j] = '#';
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) scanf(" %c", &s[i][j]);
	}
	for(int i = 0; i <= n + 1; i++) {
		for(int j = 0; j <= m + 1; j++) {
			if(s[i][j] == '#') {
				vec1[i].push_back(j);
				vec2[j].push_back(i);
			}
		}
	}
	int pos = 0;
	for(int i = 1; i <= n; i++) {
		pos = 0;
		for(int j = 1; j <= m; j++) {
			if(s[i][j] == '.') {
				res[i][j] += vec1[i][pos + 1] - vec1[i][pos] - 1; //相鄰兩個#之間.的個數
			}
			else pos++;
		}
	}
	pos = 0;
	for(int j = 1; j <= m; j++) {
		pos = 0;
		for(int i = 1; i <= n; i++) {
			if(s[i][j] == '.') {
				res[i][j] += vec2[j][pos + 1] - vec2[j][pos] - 1; //相鄰兩個#之間.的個數
			}
			else pos++;
		}
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) ans = max(ans, res[i][j] - 1); //(i, j)位置的點算了兩次
	}
	printf("%d\n", ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章