
之前没思路,我看了看答案。
思路不就来了:

简而言之,BFS那样遍历周围(上下左右均一次),如果有同色,就把这部分相邻的隔开,可以得到两块陌生人集合,就能解决,
每种颜色,最少要1次变换,最多要两次变换。
在写之前,我再优化一下:在录入当前颜色的时候,查找当前位置左方和上方的颜色,看看是否同色。
就是一这部分相邻的隔开,可以得到两块陌生人集合,就能解决
cpp
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>>arr;
vector<int>ok;
int m, n;
int reach;
void check(int a, int b)
{
int now = arr[a][b];
int up[2] = { -1,0 };
int right[2] = { 0,-1};
for (int i = 0; i < 2; i++)
{
if (a + up[i] < 0 || a + up[i] >= m || b + right[i] < 0 || b + right[i] >= n)
{
continue;
}
if (arr[a + up[i]][b + right[i]] == now)
{
if (ok[now] != -1)
{
reach++;
ok[now] = -1;
}
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> m >> n;
arr=vector<vector<int>>(m, vector<int>(n));
ok= vector<int>(5000);
int sum = 0;
reach = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
cin >> arr[i][j];
if (ok[arr[i][j]]>0)
{
check(i, j);
}
if (ok[arr[i][j]] == 0)
{
ok[arr[i][j]]++;
sum++;
}
//等于-1什么也不做
}
if (reach > 0)
{
cout << sum - reach + (reach - 1) * 2<<endl;
}
else
{
cout << sum-1 << endl;
}
}
}

超时,为什么呢?因为每次都会开一个5000大小的数组用来记住颜色,这样不行
试试键值对
cpp
#include <bits/stdc++.h>
using namespace std;
vector<vector<int>> arr; // 存储表格数据
unordered_map<int, int> ok; // 使用 unordered_map 代替数组
int m, n; // 表格的行数和列数
int reach; // 记录满足某种条件的颜色数量
// 检查函数:检查当前单元格的颜色是否与上方或左方的单元格颜色相同
void check(int a, int b) {
int now = arr[a][b]; // 当前单元格的颜色
int up[2] = { -1, 0 }; // 上方单元格的偏移量
int right[2] = { 0, -1 }; // 左方单元格的偏移量
// 检查上方和左方的单元格
for (int i = 0; i < 2; i++) {
// 检查边界条件,避免越界
if (a + up[i] < 0 || a + up[i] >= m || b + right[i] < 0 || b + right[i] >= n) {
continue; // 如果越界,跳过
}
// 如果上方或左方的单元格颜色与当前单元格相同
if (arr[a + up[i]][b + right[i]] == now) {
if (ok[now] != -1) { // 如果该颜色尚未被标记为冲突
reach++; // 增加冲突计数
ok[now] = -1; // 标记该颜色为冲突
}
}
}
}
int main() {
int t; // 测试用例的数量
cin >> t; // 读取测试用例数量
while (t--) { // 处理每个测试用例
cin >> m >> n; // 读取表格的行数和列数
arr = vector<vector<int>>(m, vector<int>(n)); // 初始化表格
ok.clear(); // 清空键值对
int sum = 0; // 记录颜色的总数
reach = 0; // 重置冲突计数
// 读取表格数据并处理
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cin >> arr[i][j]; // 读取当前单元格的颜色
if (ok[arr[i][j]] > 0) { // 如果该颜色已经出现过
check(i, j); // 检查是否与相邻单元格冲突
}
if (ok[arr[i][j]] == 0) { // 如果该颜色第一次出现
ok[arr[i][j]]++; // 标记该颜色存在
sum++; // 增加颜色总数
}
// 如果 ok[arr[i][j]] == -1,说明该颜色已经标记为冲突,无需处理
}
}
// 输出结果
if (reach > 0) { // 如果存在冲突
cout << sum - reach + (reach - 1) * 2 << endl; // 计算结果
} else { // 如果没有冲突
cout << sum - 1 << endl; // 直接输出颜色总数减 1
}
}
return 0;
}

内存小炸裂,但是成功了