这个题是个非常有意思的题,粗看上去,非常简单,无论是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);}