[COCI2019-2022#1] Zoo
$${\Huge{\odot}}$$
題意
現在你有一個 \(N \times M\) 的網格,其中一開始全部都是白色的。現在每次可以選擇一個四聯通的聯通塊,其中包含左上角和右上角,並且染成 B
顏色和 T
顏色。現在給定最終狀態,求最少需要幾次操作才能達到改狀態。\(1 \le N, M \le 1000\)。
題解
首先容易會發現,最後一次填的顏色一定是起點和終點的顏色,並且他們是在同一聯通塊裡面。也很容易想到,兩個相鄰聯通塊的顏色不同。如果聯通塊 \(A\) 和 \(B, C\) 相鄰,首先可得 \(B, C\) 不相鄰。並且如果確定聯通塊 \(A\) 比 \(B, C\) 後染,就可以知道 \(B, C\) 一起染最優。在這一次的染色中只要同時對 \(A \cap B \cap C\) 的位置染色,然後再單獨染 \(A\) 即可。
於是最佳的策略應該是最後一步染起點和終點的聯通塊,之前染與其相鄰的,在之前染與倒數第 \(2\) 次相鄰的等等。那麼只需要進行 DFS
記憶化搜尋即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};
int n, m, ans;
char c[N][N];
map<pair<int, int>, bool> used;
priority_queue<pair<int, pair<int, int> > > q;
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> c[i][j];
used[make_pair(1, 1)] = 1;
q.push(make_pair(0, make_pair(1, 1)));
while(!q.empty()){
int color = -q.top().first;
int x = q.top().second.first, y = q.top().second.second;
ans = max(ans, color);
q.pop();
for(int i = 0; i < 4; i++){
int vx = x + dx[i], vy = y + dy[i], vc = color;
if(vx < 1 || vx > n || vy < 1 || vy > m) continue;
if(c[vx][vy] == '*') continue;
if(used[make_pair(vx, vy)]) continue;
used[make_pair(vx, vy)] = 1;
if(c[x][y] != c[vx][vy]) vc++;
q.push(make_pair(-vc, make_pair(vx, vy)));
}
}
cout << ans + 1 << endl;
return 0;
}