新技巧!
了解了个新东西:虚拟射线法
题目要求我们绕树林一圈,为了使我们的搜索能满足这个条件,可以任意找一棵树,在它的下方建一堵墙,将原图分为左右两半,搜索时不许过墙,最后把墙拆掉,将图的两部分合并就可以了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#define LL long long
using namespace std;
LL read() {
LL k = 0; char c = getchar();
while(c < '0' || c > '9')
c = getchar();
while(c >= '0' && c <= '9')
k = k * 10 + c -48, c = getchar();
return k;
}
char read_c() {
char c = getchar();
while(c != '.' && c != '*' && c != 'X')
c = getchar();
return c;
}
int mapp[1010][1010];
struct zzz {
int x, y;
}q[100010]; int h = 1, t;
int fx[9] = {0, 1, 0, -1, 0, 1, 1, -1, -1},
fy[9] = {0, 0, -1, 0, 1, 1, -1, 1, -1};
int n, m;
bool judge(int xx, int yy) {
if(xx < 1 || xx > n || yy < 1 || yy > m) return 1;
return 0;
}
int main() {
//freopen("1.in", "r", stdin);
n = read(), m = read();
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j) {
char c = read_c();
if(c == 'X') mapp[i][j] = -1;
if(c == '*') q[++t].x = i, q[t].y = j, mapp[i][j] = 1;
}
srand(time(0));
int rx = rand() % n + 1, ry = rand() % m + 1;
while(!mapp[rx][ry]) rx = rand() % n + 1, ry = rand() % m + 1;
for(int i = rx + 1; i <= n; ++i) //建墙
if(mapp[i][ry] != -1) mapp[i][ry] = -2;
while(h <= t) {
int x = q[h].x, y = q[h++].y;
for(int i = 1; i <= 8; ++i) {
int xx = x + fx[i], yy = y + fy[i];
if(mapp[xx][yy] || judge(xx, yy)) continue;
mapp[xx][yy] = mapp[x][y] + 1;
q[++t].x = xx, q[t].y = yy;
}
}
int ans = 2333;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(mapp[i][j] == -2) { //拆墙+合并
for(int k = -1; k <= 1; ++k)
for(int o = -1; o <= 1; ++o) {
int xx1 = i + k, xx2 = i + o;
if(mapp[xx1][j-1] == -1 || mapp[xx2][j+1] == -1 || judge(xx1, j-1) || judge(xx2, j+1) || !mapp[xx1][j-1] || !mapp[xx2][j+1])
continue;
ans = min(ans, mapp[xx1][j-1] + mapp[xx2][j+1]);
}
}
cout << ans << endl;
return 0;
}