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);}

  • 相关阅读:
    ubuntu远程windows桌面
    spring boot 给返回值加状态 BaseData
    spring boot 拦截异常 统一处理
    IntelliJ IDEA spring boot 远程Ddbug调试
    IntelliJ IDEA 常用插件
    spring boot 请求地址带有.json 兼容处理
    spring boot 接口返回值去掉为null的字段
    spring boot 集成disconf
    Spring boot 自定义拦截器
    Linux下安装MySQL
  • 原文地址:https://www.cnblogs.com/cutemush/p/12461240.html
Copyright © 2011-2022 走看看