P1141 01迷宫
这题数据有点高级啊(这么高级的数据能不能把它变成黄题呢?不然显得我很垃圾(虽然是事实))
思路
联通块,把周围四格与自己不同的联通起来,看成一个大块,知道要的坐标属于哪个大块并数出大块有多少个点就行了
我的第一个想法是先预处理出联通块,然后直接暴力搜索,需要哪个坐标就去搜大块有几个点(想着橙题,随便做都能AC。。
(70分。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #include <bits/stdc++.h> using namespace std; int a[1005][1005]; int b[1005][1005]; bool c[1005][1005]; int n,m; void build( int x, int y, int k) { if (x>n || x==0) return ; if (y>n || y==0) return ; b[x][y]=k; if (a[x+1][y]!=a[x][y] && !b[x+1][y]) build(x+1,y,k); if (a[x-1][y]!=a[x][y] && !b[x-1][y]) build(x-1,y,k); if (a[x][y+1]!=a[x][y] && !b[x][y+1]) build(x,y+1,k); if (a[x][y-1]!=a[x][y] && !b[x][y-1]) build(x,y-1,k); } int search( int x, int y) { int ans=1; if (b[x+1][y]==b[x][y] && !c[x+1][y]) {c[x+1][y]=1; ans+=search(x+1,y);} if (b[x-1][y]==b[x][y] && !c[x-1][y]) {c[x-1][y]=1; ans+=search(x-1,y);} if (b[x][y+1]==b[x][y] && !c[x][y+1]) {c[x][y+1]=1; ans+=search(x,y+1);} if (b[x][y-1]==b[x][y] && !c[x][y-1]) {c[x][y-1]=1; ans+=search(x,y-1);} return ans; } int main() { int x,y,k=1; string s; cin>>n>>m; memset(a,100, sizeof (a)); for ( int i=1;i<=n;i++) { cin>>s; for ( int j=0;j<s.size();j++) a[i][j+1]=s[j]-48; } //输入的时候是字符串,需要逐字处理 for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++) if (!b[i][j]){ build(i,j,k); k++; } //预处理 ,属于同一个大块的都有相同的K值 for ( int k=1;k<=m;k++) { cin>>x>>y; int ans=0; memset(c,0, sizeof (c)); c[x][y]=1; ans=search(x,y); //暴力搜索所属大块有几个点 cout<<ans<<endl; } return 0; } |
然后就想着改进:感觉每次都暴力数大块有几个点,假如几个点属于同一大块,不就重复数了吗,既然这样,再预处理一下,直接输出答案不就完美了(想到这,感觉这次肯定能AC了。。
(80分。。 这数据真的高级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #include <bits/stdc++.h> using namespace std; int a[1005][1005]; int b[1005][1005]; bool c[1005][1005]; int d[1005][1005]; int n,m; void build( int x, int y, int k) { if (x>n || x==0) return ; if (y>n || y==0) return ; b[x][y]=k; if (a[x+1][y]!=a[x][y] && !b[x+1][y]) build(x+1,y,k); if (a[x-1][y]!=a[x][y] && !b[x-1][y]) build(x-1,y,k); if (a[x][y+1]!=a[x][y] && !b[x][y+1]) build(x,y+1,k); if (a[x][y-1]!=a[x][y] && !b[x][y-1]) build(x,y-1,k); } int search( int x, int y) { int ans=1; if (b[x+1][y]==b[x][y] && !c[x+1][y]) {c[x+1][y]=1; ans+=search(x+1,y);} if (b[x-1][y]==b[x][y] && !c[x-1][y]) {c[x-1][y]=1; ans+=search(x-1,y);} if (b[x][y+1]==b[x][y] && !c[x][y+1]) {c[x][y+1]=1; ans+=search(x,y+1);} if (b[x][y-1]==b[x][y] && !c[x][y-1]) {c[x][y-1]=1; ans+=search(x,y-1);} return ans; } void build1( int x, int y, int k) //预处理,在d数组直接标出属于同一个大块的点的个数 { if (x>n || x==0) return ; if (y>n || y==0) return ; d[x][y]=k; if (b[x+1][y]==b[x][y] && !d[x+1][y]) {d[x+1][y]=k; build1(x+1,y,k);} if (b[x-1][y]==b[x][y] && !d[x-1][y]) {d[x-1][y]=k; build1(x-1,y,k);} if (b[x][y+1]==b[x][y] && !d[x][y+1]) {d[x][y+1]=k; build1(x,y+1,k);} if (b[x][y-1]==b[x][y] && !d[x][y-1]) {d[x][y-1]=k; build1(x,y-1,k);} } int main() { int x,y,k=1; string s; cin>>n>>m; memset (a,100, sizeof (a)); for ( int i=1;i<=n;i++) { cin>>s; for ( int j=0;j<s.size();j++) a[i][j+1]=s[j]-48; } for ( int i=1;i<=n;i++) for ( int j=1;j<=n;j++) if (!b[i][j]){ build(i,j,k); memset (c,0, sizeof (c)); c[i][j]=1; int ans=search(i,j); //搜索出大块有几个点 build1(i,j,ans); //预处理 k++; } for ( int k=1;k<=m;k++) { cin>>x>>y; cout<<d[x][y]<<endl; //直接输出结果 } return 0; } |
然后实在撑不住,去看了题解。。
每次碰到没搜过的就进行一次搜索,碰到的就直接输出(用数组模拟队列来储存属于同一大块的点的坐标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #include <bits/stdc++.h> using namespace std; int a[1005][1005]; int c[1005][1005]; int d[1005][1005]; int xx[10000005],yy[1000005]; int n,m; void search( int x, int y) { int t=1,h=0,ans=0; while (h<t) //bfs的队列 { h++; x=xx[h]; y=yy[h]; if (a[x+1][y]!=a[x][y] && !c[x+1][y] && x+1<=n) {t++; c[x+1][y]=1; xx[t]=x+1; yy[t]=y;} if (a[x-1][y]!=a[x][y] && !c[x-1][y] && x-1>0) {t++; c[x-1][y]=1; xx[t]=x-1; yy[t]=y;} if (a[x][y+1]!=a[x][y] && !c[x][y+1] && y+1<=n) {t++; c[x][y+1]=1; xx[t]=x; yy[t]=y+1;} if (a[x][y-1]!=a[x][y] && !c[x][y-1] && y-1>0) {t++; c[x][y-1]=1; xx[t]=x; yy[t]=y-1;} } for ( int i=1;i<=t;i++) d[xx[i]][yy[i]]=t; //每个属于大块的点都标记上大块点的个数 return ; } int main() { int x,y,k=1; string s; cin>>n>>m; memset (a,100, sizeof (a)); for ( int i=1;i<=n;i++) { cin>>s; for ( int j=0;j<s.size();j++) a[i][j+1]=s[j]-48; } for ( int k=1;k<=m;k++) { cin>>x>>y; if (!d[x][y]) {c[x][y]=1; xx[1]=x; yy[1]=y; search(x,y);} //如果没搜过就搜 cout<<d[x][y]<<endl; } return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通