题解 P3671 【[USACO17OPEN]Where's Bessie? 贝西在哪呢】
最近一直在刷老题目,很久没有发过题解了(嘻嘻,还是一如既往地菜)
这是一道较为繁琐的搜索题,难并不在搜索过程,而是在判断“两种颜色一种构成一个连通块,另一种形成两个或两个以上的连通块”和“是否被其它PCL覆盖”这两个过程(也就是模拟)。如果没有很好的处理方法,代码很容易写得十分冗长。我这份代码跑了176ms,比楼下两位的题解快一些,写法稍简洁一些,希望能给大家以帮助。
code:
#include<bits/stdc++.h>
using namespace std;
const int dx[4]={0,-1,0,1}; //两个方向数组,dfs/bfs标配
const int dy[4]={-1,0,1,0};
int n,cnt=0,sum[100],ans=0; //ans存储答案
char a[25][25]; //a数组存储矩阵
bool f[100],v[25][25]; //v数组判断是否搜过,f数组用于记录一个PCL内的某种颜色是否出现过
struct pcl
{
int x1,y1,x2,y2;
}s[50000]; //s数组存储每个PCL的左上角及右下角的横纵坐标
void dfs(int x,int y,int n1,int n2,int m1,int m2)
{ //深搜划分连通块,注意判断越界的标准不再是整个矩阵的1和n了
for(int i=0; i<4; i++)
{
int x1=x+dx[i],y1=y+dy[i];
if(x1<n1||x1>n2||y1<m1||y1>m2||v[x1][y1]||a[x1][y1]!=a[x][y]) continue;
v[x1][y1]=true;
dfs(x1,y1,n1,n2,m1,m2); //递归深搜
}
}
bool PCL(int u1,int v1,int u2,int v2) //判断当前矩阵是否是PCL
{
int col=0; char c1,c2; //c1和c2存储矩阵中的两种不同颜色
memset(f,0,sizeof(f));
for(int i=u1; i<=u2; i++) //以下统计当前矩阵中的不同颜色的个数
for(int j=v1; j<=v2; j++)
if(!f[a[i][j]])
{
f[a[i][j]]=true;
col++;
if(col==1) c1=a[i][j];
if(col==2) c2=a[i][j];
}
if(col!=2) return false; //如果不同颜色数不为2,返回false
memset(sum,0,sizeof(sum)); //sum数组存储每个颜色的连通块的个数
memset(v,0,sizeof(v));
for(int i=u1; i<=u2; i++)
for(int j=v1; j<=v2; j++)
if(!v[i][j]) //如果未搜索过
{
v[i][j]=true; //标记
sum[a[i][j]]++; //sum数组++
dfs(i,j,u1,u2,v1,v2); //深搜
}
if((sum[c1]==1&&sum[c2]>=2)||(sum[c1]>=2&&sum[c2]==1)) return true; //若满足条件2则返回true表示当前矩阵是一个PCL
else return false;
}
bool judge(int x) //去重过程,判断第x个PCL是否被别的PCL所覆盖
{
for(int i=1; i<=cnt; i++)
{
if(i!=x&&s[i].x1<=s[x].x1&&s[i].y1<=s[x].y1&&s[i].x2>=s[x].x2&&s[i].y2>=s[x].y2)
return false;
}
return true;
}
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) cin>>a[i][j]; //读入矩阵
for(int i=1; i<=n; i++) //四重循环暴力枚举每个矩阵的左上角和右下角坐标并做判断
for(int j=1; j<=n; j++)
for(int k=i; k<=n; k++)
for(int l=j; l<=n; l++)
if(PCL(i,j,k,l))
{ //若当前矩阵是PCL则记录下来
cnt++;
s[cnt].x1=i; s[cnt].y1=j; s[cnt].x2=k; s[cnt].y2=l;
}
for(int i=1; i<=cnt; i++) //完成去重,累计答案
if(judge(i)) ans++;
cout<<ans<<endl; //输出
return 0;
}
希望对您有帮助!(话说做USACO月赛题的人好少)