小明有一套玩具,一共包含NxM个部件。这些部件摆放在一个包含NxM个小格子的玩具盒中,每个小格子中恰好摆放一个部件。
每一个部件上标记有一个0~9的整数,有可能有多个部件标记相同的整数。
小明对玩具的摆放有特殊的要求:标记相同整数的部件必须摆在一起,组成一个矩形形状。如以下摆放是满足要求的:
00022
00033
44444
12244
12244
12233
01234
56789
以下摆放不满足要求:
11122
11122
33311
111111
122221
122221
111111
11122
11113
33333
给出一种摆放方式,请你判断是否符合小明的要求。
输入
输入包含多组数据。
第一行包含一个整数T,代表数据组数。 (1 <= T <= 10)
以下包含T组数据。
每组数据第一行包含两个整数N和M。 (1 <= N, M <= 10)
以下包含N行M列的矩阵,代表摆放方式。
输出
对于每组数据,输出YES或者NO代表是否符合小明的要求。
样例输入
3
3 5
00022
00033
44444
3 5
11122
11122
33311
2 5
01234
56789
样例输出
YES
NO
YES
方法一:区域染色
核心是检查矩形这:由于是矩形,需要记录搜到的最远位置(即矩形右下角 ex, ey),检查是否是矩形就是枚举面积为 (ex-i) × (ey-j) 的矩形是否在一次遍历后染成同一种颜色的格子的数量等于该颜色全局的数量且数量等于 (ex-i) × (ey-j)
#include<bits/stdc++.h>
using namespace std;
const int N=15, d[4][2] = { {1,0},{0,-1},{0,1},{-1,0} };
int ex, ey, n, m, cnt[N], now[N], mark[N][N];
char g[N][N];
void dfs(int i, int j, int c) {
ex=max(ex, i), ey=max(ey, j);
mark[i][j]=c, now[g[i][j]-'0']++;
for (int k=0; k<4; k++) {
int ni=i+d[k][0], nj=j+d[k][1];
if (ni>=0 && ni<n && nj>=0 && nj<m && mark[ni][nj]==0 && g[i][j]==g[ni][nj]) {
dfs(ni, nj, c);
}
}
}
bool chk() {
int color=1;
for (int i=0; i<n; i++)
for (int j=0; j<m; j++) if (mark[i][j]==0) {
ex=-1, ey=-1;
dfs(i, j, color++);
if (now[g[i][j]-'0'] != cnt[g[i][j]-'0']) return false;
for (int ii=i; ii<=ex; ii++)
for (int jj=j; jj<=ey; jj++) if (mark[ii][jj]!=mark[i][j])
return false;
}
return true;
}
int main() {
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T; cin>>T;
while (T--) {
cin>>n>>m;
memset(cnt, 0, sizeof cnt), memset(now, 0, sizeof now), memset(mark, 0, sizeof mark);
for (int i=0; i<n; i++)
for (int j=0; j<m; j++) {
cin>>g[i][j];
cnt[g[i][j]-'0']++;
}
cout << (chk() ? "YES" : "NO") << '\n';
}
return 0;
}