给出一个 (n imes m) 的矩阵,你可以每次按照字母顺序添加横向或纵向的一条链,这条链会是 a~z 这 (26) 个小写字母中的一个,并且会覆盖原来的链。现在给出一个操作后的矩阵,要求回答是否可能形成这种情况,且每条链是从哪个点到哪个点。
Solution
倒序处理,将字母一层一层剥开,同时记录前层中留下来的“无关”位置,即该位置由于先前被覆盖,现在可有可无
于是我们对于当前字母 c
,找到 c
字母的四边界,检查这是否是一条直链,如果不是则退出
如果是,则检查这条直链范围内加上无关字母是否能填满,如果不能则退出
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
char a[N][N];
int t,n,m,l[N],r[N],u[N],b[N],t1[N],t2[N],t3[N],t4[N];
int calc(int c) {
int cnt=0;
for(int i=b[c];i<=u[c];i++) {
for(int j=l[c];j<=r[c];j++) {
if(a[i][j]=='*'||a[i][j]==c) ++cnt;
a[i][j]='*';
}
}
return cnt;
}
void putss(string s) {cout<<s<<endl;}
signed main() {
ios::sync_with_stdio(false);
cin>>t;
while(t--) {
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i]+1;
for(int i='a';i<='z';i++) l[i]=b[i]=1e9,r[i]=u[i]=t1[i]=t2[i]=t3[i]=t4[i]=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i][j]>='a' && a[i][j]<='z') {
l[a[i][j]]=min(l[a[i][j]],j);
r[a[i][j]]=max(r[a[i][j]],j);
b[a[i][j]]=min(b[a[i][j]],i);
u[a[i][j]]=max(u[a[i][j]],i);
}
}
}
int cnt=0;
for(int i='z';i>='a';--i) {
if(u[i]==0) continue;
if(u[i]!=b[i] && l[i]!=r[i]) goto EN;
if(calc(i)!=(r[i]-l[i]+1)*(u[i]-b[i]+1)) goto EN;
}
putss("YES");
for(int i='a';i<='z';i++) if(u[i]) cnt=i-'a'+1;
cout<<cnt<<endl;
for(int i='y';i>='a';i--) if(u[i]==0) {
b[i]=b[i+1];
u[i]=u[i+1];
l[i]=l[i+1];
r[i]=r[i+1];
}
for(int i='a';i<='z';i++) if(u[i]) cout<<b[i]<<" "<<l[i]<<" "<<u[i]<<" "<<r[i]<<endl;
continue;
EN: putss("NO");
}
}