P3671 [USACO17OPEN] Where's Bessie? S 题解
我们先枚举所有子矩阵,验证其在不考虑重叠的情况下是否为 PCL 矩阵(dfs 求一遍联通块即可)。
然后将所有满足条件的矩阵存下来,最后朴素判断每个矩阵是否被其他矩阵包括,若没有矩阵包括它,则其对于答案的贡献为 \(1\),累加所有贡献即为最终结果。
时间复杂度是 \(O(n^6)\) 的。
思路很简单,讲一下坑点:
-
dfs 求联通块时,注意坐标范围不是 \(1 \sim n\) 而是当前子矩阵的左上角坐标 \(\sim\) 右下角坐标。
-
枚举子矩阵时,左下角坐标可以等于右下角坐标,所以注意循环变量的初始值设定。
代码(略有压行):
#include<bits/stdc++.h> #define int long long #define ft first #define sc second using namespace std; int n,ans,tot,dx[]={0,0,-1,1},dy[]={-1,1,0,0}; char mp[31][31]; bool fl[31][31]; //标记联通块 pair<pair<int,int>,pair<int,int> > mat[160031]; //存放合法矩阵 void dfs(int x,int y,int n1,int n2,int m1,int m2,char c){ //dfs 求联通块 fl[x][y]=1; for(int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(xx>=n1&&xx<=n2&&yy>=m1&&yy<=m2&&!fl[xx][yy]&&mp[xx][yy]==c) dfs(xx,yy,n1,n2,m1,m2,c); } } bool check(int x,int y,int xx,int yy){ //校验矩阵 char c1=' ',c2=' '; int cnt1=0,cnt2=0; //分别表示:两种不同类型的字符、两种字符的联通块数量 for(int i=x;i<=xx;i++){ for(int j=y;j<=yy;j++){ if(c1==' '){ c1=mp[i][j]; break; } } } //找出第一种字符 for(int i=x;i<=xx;i++){ for(int j=y;j<=yy;j++){ if(c2==' '&&mp[i][j]!=c1){ c2=mp[i][j]; break; } } } //找出第二种字符 for(int i=x;i<=xx;i++) for(int j=y;j<=yy;j++) if(mp[i][j]!=c1&&mp[i][j]!=c2) return 0; //若字符种类超过两种一定不合法 memset(fl,0,sizeof(fl)); for(int i=x;i<=xx;i++) for(int j=y;j<=yy;j++) if(mp[i][j]==c1&&!fl[i][j]) cnt1++,dfs(i,j,x,xx,y,yy,c1); //求第一种字符的联通块数量 for(int i=x;i<=xx;i++) for(int j=y;j<=yy;j++) if(mp[i][j]==c2&&!fl[i][j]) cnt2++,dfs(i,j,x,xx,y,yy,c2); //求第二种字符的联通块数量 if((cnt1==1&&cnt2>1)||(cnt1>1&&cnt2==1)) return 1; return 0; //若一种字符的联通块数量>1且另一种=1则合法,否则不合法 } signed main(){ ios::sync_with_stdio(0); cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>mp[i][j]; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int ii=i;ii<=n;ii++) for(int jj=j;jj<=n;jj++) if(check(i,j,ii,jj)) mat[++tot].ft.ft=i,mat[tot].ft.sc=j,mat[tot].sc.ft=ii,mat[tot].sc.sc=jj; //存放矩阵 for(int i=1;i<=tot;i++){ bool f=1; for(int j=1;j<=tot;j++) if(i!=j&&mat[i].ft.ft>=mat[j].ft.ft&&mat[i].ft.sc>=mat[j].ft.sc&&mat[i].sc.ft<=mat[j].sc.ft&&mat[i].sc.sc<=mat[j].sc.sc){ f=0; break; } //遍历矩阵判断是否覆盖 if(f) ans++; //累加贡献 } cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现