CF1579C题解
思路
依次枚举每一个黑色点,然后一枚举到的点为勾最靠下的那个点,如图种红色圈的部分。
然后搜索左上角和右上角,判断是否合法,即连续格子长度符合要求。
因为他的连续格子长度不一定是 \(d\),而长度越长是对其他勾没有影响,而覆盖的越多一定不或更差,所以我们就想要这个连续格子长度尽量长。而两边长度需要对称,所以取最小的一边。这个操作可以在判断时求。
如果判断合法,则把这个勾能够染成黑色的格子标记。
最后看一下是不是所有黑色格子都被标记过就好了。
AC CODE
#include<bits/stdc++.h>
using namespace std;
int n,m,d,dx[4]={-1,-1,1,1},dy[4]={-1,1,-1,1},vis[20][20],vis2[20][20],minn=1e9;
char c[20][20];
bool dfs(int x,int y,int f,int t){//左上角或右上角方向染色格子长度是否大于等于d
x+=dx[f];
y+=dy[f];
if(vis[x][y]==0){
if(t<d)return false;
minn=min(minn,t);
return true;
}
if(x<1||y<1||y>m)return false;
dfs(x,y,f,t+1);
}
void dfs2(int x,int y,int f,int t){//标记勾能染到的格子
if(t>minn)return;
vis2[x][y]=1;
x+=dx[f];
y+=dy[f];
dfs2(x,y,f,t+1);
}
int main(){
int T;
cin>>T;
while(T--){
memset(vis,0,sizeof vis);
memset(vis2,0,sizeof vis2);
cin>>n>>m>>d;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>c[i][j];
if(c[i][j]=='*')vis[i][j]=1;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(vis[i][j]){
minn=1e9;
if(dfs(i,j,0,0)&&dfs(i,j,1,0)){//判断
vis2[i][j]=1;//标记
dfs2(i,j,0,0);
dfs2(i,j,1,0);
}
}
}
}
bool ok=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c[i][j]=='*'){//所有黑色格子是否被标记
if(!vis2[i][j])ok=0;
}
}
}
if(ok)cout<<"YES";
else cout<<"NO";
cout<<endl;
}
return 0;
}