zoukankan      html  css  js  c++  java
  • 国家宝藏

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

  • 相关阅读:
    鸿合爱学班班.kl课件转ppt课件
    Mac下Android Studio添加忽略文件的方法
    Android中处理PPI
    Mac下配置全局gradlew命令
    Application启动图
    图像合成模式XferMode
    path绘制
    drawArc 画扇形 画弧线
    okhttp请求完整流程图
    责任链模式
  • 原文地址:https://www.cnblogs.com/cutemush/p/12461240.html
Copyright © 2011-2022 走看看