乍看题目,感觉不难写,处理图,把块变成节点,搜索,结果处理建图的时候越写越麻烦,没思路,只好抄题解了
用并查集的能理解,还有的搜索写了些剪枝,不理解。就放抄的并查集题解吧。
/*
每个数字块是一个整体,用并查集维护大小 。
给所有相邻数字块建边 ,并根据颜色排序
处理每个数字块与那些数字块相连,维护一个颜色连接着 哪些数字块。
枚举处理所有相邻的数字块方案,已经根据数字值安排在一起。
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <vector>
#include<numeric>
using namespace std;
struct Edge {
int u, v, c1, c2;
Edge() {}
Edge(int u, int v, int c1, int c2) : u(u), v(v), c1(min(c1, c2)), c2(max(c1, c2)) {}
bool operator<(const Edge& rhs) const {
if (c1 != rhs.c1)
return c1 < rhs.c1;
return c2 < rhs.c2;
}
};
const int N = 252;
int n, ecnt;
int f[N * N], sz[N * N], szcp[N * N];
int a[N][N];
Edge ed[N * N * 2];
vector<int> sts[1000010];
int find(int x);
int gind(int x, int y);
void merge(int x, int y);
int main() {
int a1 = 0, a2 = 0;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
scanf("%d", &a[i][j]);
for(int i=1; i<=n*n; i++) f[i]=i;
for(int i=1; i<=n*n; i++) sz[i]=1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {//向右下方合并相同的区域
if (i != n && a[i][j] == a[i + 1][j])
merge(gind(i, j), gind(i + 1, j));
if (j != n && a[i][j] == a[i][j + 1])
merge(gind(i, j), gind(i, j + 1));
a1 = max(a1, sz[find(gind(i, j))]);//合并的过程中找最大值
}
}
for (int i = 1; i <= n; ++i)//再扫描一遍,找相邻的两个区域
for (int j = 1; j <= n; ++j) {
if (i != n && a[i][j] != a[i + 1][j]) {//建右侧边 ,二维坐标转换为一维数字。
ed[++ecnt] = Edge(find(gind(i, j)), find(gind(i + 1, j)), a[i][j], a[i + 1][j]);
}
if (j != n && a[i][j] != a[i][j + 1]) {//建下方边
ed[++ecnt] = Edge(find(gind(i, j)), find(gind(i, j + 1)), a[i][j], a[i][j + 1]);
}
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
int ind = gind(i, j);
if (find(ind) == ind)//以颜色为节点,当前颜色连接着那些块
sts[a[i][j]].push_back(ind);
}
sort(ed + 1, ed + ecnt + 1);
memcpy(szcp, sz, sizeof(sz));
for (int i = 1; i <= ecnt; ) {//处理边,也就是这些相邻块
int c1 = ed[i].c1, c2 = ed[i].c2;//排序后的相邻颜色已经在一起
while (ed[i].c1 == c1 && ed[i].c2 == c2) {//处理在一起的这些颜色
merge(ed[i].u, ed[i].v);
a2 = max(a2, sz[find(ed[i].u)]);
++i;
}//处理完一种颜色匹配后,状态恢复,以备处理另一种颜色。
for (int j=0; j<sts[c1].size(); j++) {
int u=sts[c1][j];
f[u] = u;
sz[u] = szcp[u];
}
for (int j=0; j<sts[c2].size(); j++) {
int u=sts[c2][j];
f[u] = u;
sz[u] = szcp[u];
}
}
printf("%d\n%d\n", a1, a2);
return 0;
}
inline int gind(int x, int y) {
return (x - 1) * n + y;
}
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
void merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y)
return;
sz[x] += sz[y];
f[y] = x;
}