这个题是个非常有意思的题,粗看上去,非常简单,无论是BFS还是DFS,扫一下就知道有多少个连通块了,但发现内存只有3M,则说明没有办法将整个图保存起来。于是无法进行遍历点的操作了。但我们还是可以保存二行的地图。于是可以针对当前点[i,j]进行分类讨论
如果[i,j]是一个宝藏点,则[i-1,j],[i,j-1]这两个点一共有四种状态
1:如果它们都不是宝藏点,则[i,j]这个点是个新开的宝藏点,独立成一块。
2:如果仅[i-1,j]是宝藏点,则[i,j]与之连成一块,[i-1,j]属于哪一块,[i,j]也是属于哪一块
3:如果仅[i,j-1]是宝藏点,情况同上
4:如果[i-1,j],[i,j-1]都是宝藏点,则它们可以通过[i,j]点进行连通。此时看下它们所属的连通块的编号是否一致
如果不一致,则连通后,连通块的总个数减少一个。
如果[i,j]不是一个宝藏点,则不用管它了。
当然此题的数据是构造过的,如果出一些极端数据,例如
01点均是相间出现,则连通块个数为n*n/2,这种方法仍是过不了的。
此题可用并查集完成,当然如果有人能在仅会数组的情况下,完成此题,则说明思维能力超人。所以思维能力才是最关键的,知识掌握量的多与少是另一回事。
#include<iostream> #include<cstdio> using namespace std; int k,t,p,q,n,tot,ans; int father[50010]; bool mapp[2][50010]; int f[2][50010]; int find(int x) { if(x!=father[x]) father[x]=find(father[x]); return father[x]; } int main() { scanf("%d",&n); for(int i=1;i<=50000;i++) father[i]=i; //这里并不是指每个点的父亲点是谁,而是每个连通块的父亲点是谁。 //因为后面涉及连通块的合并,当某些点属于同一个连通块而又发生合并时 //需要知道每个连通块的父亲点是谁,由此来决定当连通两个连通块时,总块数要不要减少1 t=0; for(int i=1;i<=n;i++) { t^=1; for(int j=1;j<=n;j++) { scanf("%d",&k); if(k==0) mapp[t][j]=true; else mapp[t][j]=false; } for(int j=1;j<=n;j++) { if(mapp[t][j]) //如果当前行是宝藏 { if(!mapp[t^1][j]&&!mapp[t][j-1]) //其上方与左边都不是宝藏的话,则自成一块 { tot++;//连通块编号 ans++;//目前有多少个连通块 f[t][j]=tot; } else if(!mapp[t^1][j]&&mapp[t][j-1])//如果上方不是,左边是 f[t][j]=f[t][j-1];//跟着左边走 else if(mapp[t^1][j]&&!mapp[t][j-1]) f[t][j]=f[t^1][j]; //跟着上方走 else //上方与左边都是宝藏的话 { f[t][j]=f[t^1][j]; p=find(f[t^1][j]); q=find(f[t][j-1]); if(p!=q) //如果上方与左边不是一个块 { father[p]=min(p,q); father[q]=min(p,q); ans--;//进行连通,总答案个数减少1 } } } } } printf("%d",ans); }
#include<iostream>#include<cstdio>using namespace std;int k,t,p,q,n,tot,ans;int father[50010];bool mapp[2][50010];int f[2][50010];int find(int x){ if(x!=father[x]) father[x]=find(father[x]); return father[x];}int main(){ scanf("%d",&n); for(int i=1;i<=50000;i++) father[i]=i; //这里并不是指每个点的父亲点是谁,而是每个连通块的父亲点是谁。//因为后面涉及连通块的合并,当某些点属于同一个连通块而又发生合并时//需要知道每个连通块的父亲点是谁,由此来决定当连通两个连通块时,总块数要不要减少1 t=0; for(int i=1;i<=n;i++) { t^=1; for(int j=1;j<=n;j++) { scanf("%d",&k); if(k==0) mapp[t][j]=true; else mapp[t][j]=false; } for(int j=1;j<=n;j++) { if(mapp[t][j]) //如果当前行是宝藏 { if(!mapp[t^1][j]&&!mapp[t][j-1]) //其上方与左边都不是宝藏的话,则自成一块 { tot++;//连通块编号 ans++;//目前有多少个连通块 f[t][j]=tot; } else if(!mapp[t^1][j]&&mapp[t][j-1])//如果上方不是,左边是 f[t][j]=f[t][j-1];//跟着左边走 else if(mapp[t^1][j]&&!mapp[t][j-1]) f[t][j]=f[t^1][j]; //跟着上方走 else //上方与左边都是宝藏的话 { f[t][j]=f[t^1][j]; p=find(f[t^1][j]); q=find(f[t][j-1]); if(p!=q) //如果上方与左边不是一个块 { father[p]=min(p,q); father[q]=min(p,q); ans--;//进行连通,总答案个数减少1 } } } } } printf("%d",ans);}