1 条题解

  • 0
    @ 2025-8-24 21:51:27

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 微雨燕双飞
    **

    搬运于2025-08-24 21:51:27,当前版本为作者最后更新于2018-09-01 18:38:50,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    最近一直在刷老题目,很久没有发过题解了(嘻嘻,还是一如既往地菜)

    这是一道较为繁琐的搜索题,难并不在搜索过程,而是在判断“两种颜色一种构成一个连通块,另一种形成两个或两个以上的连通块”和“是否被其它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月赛题的人好少)

    • 1

    信息

    ID
    1145
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者